From a4d744aa531793cc6e32dfb48ae8ab6b3b9de7f1 Mon Sep 17 00:00:00 2001 From: woodser Date: Mon, 21 Jul 2025 09:56:57 -0400 Subject: [PATCH] remove inverted crypto prices; always use price per XMR (base/quote) (#1821) --- .../witness/AccountAgeWitnessService.java | 4 +- .../haveno/core/api/CoreOffersService.java | 20 +-- .../haveno/core/api/CorePriceService.java | 31 +--- .../haveno/core/api/CoreTradesService.java | 2 +- .../java/haveno/core/api/model/OfferInfo.java | 4 +- .../java/haveno/core/api/model/TradeInfo.java | 2 +- .../java/haveno/core/locale/CurrencyUtil.java | 17 +- .../core/monetary/CryptoExchangeRate.java | 21 ++- .../main/java/haveno/core/monetary/Price.java | 2 +- .../monetary/TraditionalExchangeRate.java | 160 +++++++++--------- .../alerts/market/MarketAlerts.java | 33 +--- .../haveno/core/offer/CreateOfferService.java | 6 +- .../main/java/haveno/core/offer/Offer.java | 58 ++----- .../haveno/core/offer/OfferBookService.java | 6 +- .../haveno/core/offer/OfferFilterService.java | 4 +- .../java/haveno/core/offer/OfferForJson.java | 11 +- .../java/haveno/core/offer/OfferUtil.java | 4 +- .../haveno/core/offer/OpenOfferManager.java | 13 +- .../core/offer/TriggerPriceService.java | 14 +- .../offer/placeoffer/tasks/ValidateOffer.java | 4 +- .../core/offer/takeoffer/TakeOfferModel.java | 4 +- .../core/payment/PaymentAccountUtil.java | 4 +- .../core/payment/ReceiptPredicates.java | 2 +- .../core/provider/price/PriceFeedService.java | 14 +- .../core/provider/price/PriceProvider.java | 16 +- .../main/java/haveno/core/trade/Trade.java | 12 +- .../java/haveno/core/trade/TradeUtil.java | 36 ++-- .../trade/protocol/tasks/ApplyFilter.java | 4 +- .../tasks/VerifyPeersAccountAgeWitness.java | 2 +- .../trade/statistics/TradeStatistics3.java | 45 +++-- .../statistics/TradeStatisticsForJson.java | 26 +-- .../statistics/TradeStatisticsManager.java | 45 ++++- .../haveno/core/util/AveragePriceUtil.java | 6 +- .../main/java/haveno/core/util/PriceUtil.java | 44 +++-- .../resources/i18n/displayStrings.properties | 20 +-- .../i18n/displayStrings_cs.properties | 20 +-- .../i18n/displayStrings_de.properties | 12 +- .../i18n/displayStrings_es.properties | 12 +- .../i18n/displayStrings_fa.properties | 12 +- .../i18n/displayStrings_fr.properties | 12 +- .../i18n/displayStrings_it.properties | 12 +- .../i18n/displayStrings_ja.properties | 12 +- .../i18n/displayStrings_pt-br.properties | 12 +- .../i18n/displayStrings_pt.properties | 12 +- .../i18n/displayStrings_ru.properties | 12 +- .../i18n/displayStrings_th.properties | 12 +- .../i18n/displayStrings_tr.properties | 20 +-- .../i18n/displayStrings_vi.properties | 12 +- .../i18n/displayStrings_zh-hans.properties | 12 +- .../i18n/displayStrings_zh-hant.properties | 12 +- .../java/haveno/core/monetary/PriceTest.java | 8 +- .../core/payment/ReceiptPredicatesTest.java | 2 +- .../haveno/daemon/grpc/GrpcPriceService.java | 3 - .../components/PeerInfoIconTrading.java | 2 +- .../desktop/main/market/MarketView.java | 2 +- .../market/offerbook/OfferBookChartView.java | 16 +- .../offerbook/OfferBookChartViewModel.java | 27 ++- .../main/market/spread/SpreadViewModel.java | 34 ++-- .../main/market/trades/ChartCalculations.java | 18 +- .../market/trades/TradesChartsViewModel.java | 2 +- .../desktop/main/offer/MutableOfferView.java | 21 +-- .../main/offer/MutableOfferViewModel.java | 51 ++---- .../haveno/desktop/main/offer/OfferView.java | 14 +- .../desktop/main/offer/OfferViewUtil.java | 2 +- .../offerbook/CryptoOfferBookViewModel.java | 4 +- .../offerbook/FiatOfferBookViewModel.java | 2 +- .../main/offer/offerbook/OfferBook.java | 2 +- .../offer/offerbook/OfferBookListItem.java | 4 +- .../main/offer/offerbook/OfferBookView.java | 14 +- .../offer/offerbook/OfferBookViewModel.java | 24 +-- .../offerbook/OtherOfferBookViewModel.java | 4 +- .../offer/takeoffer/TakeOfferDataModel.java | 12 +- .../main/offer/takeoffer/TakeOfferView.java | 8 +- .../offer/takeoffer/TakeOfferViewModel.java | 18 +- .../main/overlays/windows/ContractWindow.java | 2 +- .../overlays/windows/OfferDetailsWindow.java | 23 +-- .../overlays/windows/TradeDetailsWindow.java | 6 +- .../cloneoffer/CloneOfferDataModel.java | 6 +- .../portfolio/cloneoffer/CloneOfferView.java | 2 +- .../closedtrades/ClosedTradesListItem.java | 4 +- .../editoffer/EditOfferDataModel.java | 6 +- .../portfolio/editoffer/EditOfferView.java | 2 +- .../failedtrades/FailedTradesViewModel.java | 4 +- .../openoffer/OpenOffersDataModel.java | 2 +- .../openoffer/OpenOffersViewModel.java | 8 +- .../pendingtrades/PendingTradesListItem.java | 2 +- .../pendingtrades/steps/TradeStepView.java | 2 +- .../haveno/desktop/util/DisplayUtils.java | 59 ++----- .../createoffer/CreateOfferViewModelTest.java | 2 +- 89 files changed, 588 insertions(+), 728 deletions(-) diff --git a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java index 978b6dd715..eb36f0aa0f 100644 --- a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java +++ b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java @@ -654,7 +654,7 @@ public class AccountAgeWitnessService { Date peersCurrentDate, ErrorMessageHandler errorMessageHandler) { checkNotNull(offer); - final String currencyCode = offer.getCurrencyCode(); + final String currencyCode = offer.getCounterCurrencyCode(); final BigInteger defaultMaxTradeLimit = offer.getPaymentMethod().getMaxTradeLimit(currencyCode); BigInteger peersCurrentTradeLimit = defaultMaxTradeLimit; if (!hasTradeLimitException(peersWitness)) { @@ -673,7 +673,7 @@ public class AccountAgeWitnessService { "\nPeers trade limit=" + peersCurrentTradeLimit + "\nOffer ID=" + offer.getShortId() + "\nPaymentMethod=" + offer.getPaymentMethod().getId() + - "\nCurrencyCode=" + offer.getCurrencyCode(); + "\nCurrencyCode=" + offer.getCounterCurrencyCode(); log.warn(msg); errorMessageHandler.handleErrorMessage(msg); } diff --git a/core/src/main/java/haveno/core/api/CoreOffersService.java b/core/src/main/java/haveno/core/api/CoreOffersService.java index 3ee7e047f1..a3b044f3b1 100644 --- a/core/src/main/java/haveno/core/api/CoreOffersService.java +++ b/core/src/main/java/haveno/core/api/CoreOffersService.java @@ -149,7 +149,7 @@ public class CoreOffersService { List getMyOffers(String direction, String currencyCode) { return getMyOffers().stream() .filter(o -> offerMatchesDirectionAndCurrency(o.getOffer(), direction, currencyCode)) - .sorted(openOfferPriceComparator(direction, CurrencyUtil.isTraditionalCurrency(currencyCode))) + .sorted(openOfferPriceComparator(direction)) .collect(Collectors.toList()); } @@ -336,7 +336,7 @@ public class CoreOffersService { String sourceOfferId, Consumer resultHandler, ErrorMessageHandler errorMessageHandler) { - long triggerPriceAsLong = PriceUtil.getMarketPriceAsLong(triggerPriceAsString, offer.getCurrencyCode()); + long triggerPriceAsLong = PriceUtil.getMarketPriceAsLong(triggerPriceAsString, offer.getCounterCurrencyCode()); openOfferManager.placeOffer(offer, useSavingsWallet, triggerPriceAsLong, @@ -353,8 +353,7 @@ public class CoreOffersService { if ("".equals(direction)) direction = null; if ("".equals(currencyCode)) currencyCode = null; var offerOfWantedDirection = direction == null || offer.getDirection().name().equalsIgnoreCase(direction); - var counterAssetCode = CurrencyUtil.isCryptoCurrency(currencyCode) ? offer.getOfferPayload().getBaseCurrencyCode() : offer.getOfferPayload().getCounterCurrencyCode(); - var offerInWantedCurrency = currencyCode == null || counterAssetCode.equalsIgnoreCase(currencyCode); + var offerInWantedCurrency = currencyCode == null || offer.getCounterCurrencyCode().equalsIgnoreCase(currencyCode); return offerOfWantedDirection && offerInWantedCurrency; } @@ -366,17 +365,12 @@ public class CoreOffersService { : priceComparator.get(); } - private Comparator openOfferPriceComparator(String direction, boolean isTraditional) { + private Comparator openOfferPriceComparator(String direction) { // A buyer probably wants to see sell orders in price ascending order. // A seller probably wants to see buy orders in price descending order. - if (isTraditional) - return direction.equalsIgnoreCase(OfferDirection.BUY.name()) - ? openOfferPriceComparator.get().reversed() - : openOfferPriceComparator.get(); - else - return direction.equalsIgnoreCase(OfferDirection.SELL.name()) - ? openOfferPriceComparator.get().reversed() - : openOfferPriceComparator.get(); + return direction.equalsIgnoreCase(OfferDirection.BUY.name()) + ? openOfferPriceComparator.get().reversed() + : openOfferPriceComparator.get(); } private long priceStringToLong(String priceAsString, String currencyCode) { diff --git a/core/src/main/java/haveno/core/api/CorePriceService.java b/core/src/main/java/haveno/core/api/CorePriceService.java index 54688f97e4..d4ed3257cf 100644 --- a/core/src/main/java/haveno/core/api/CorePriceService.java +++ b/core/src/main/java/haveno/core/api/CorePriceService.java @@ -78,7 +78,7 @@ class CorePriceService { } else if (!marketPrice.isExternallyProvidedPrice()) { throw new IllegalArgumentException("Price is not available externally: " + currencyCode); // TODO: return more complex Price type including price double and isExternal boolean } - return mapPriceFeedServicePrice(marketPrice.getPrice(), marketPrice.getCurrencyCode()); + return marketPrice.getPrice(); } /** @@ -87,8 +87,7 @@ class CorePriceService { public List getMarketPrices() throws ExecutionException, InterruptedException, TimeoutException { return priceFeedService.requestAllPrices().values().stream() .map(marketPrice -> { - double mappedPrice = mapPriceFeedServicePrice(marketPrice.getPrice(), marketPrice.getCurrencyCode()); - return new MarketPriceInfo(marketPrice.getCurrencyCode(), mappedPrice); + return new MarketPriceInfo(marketPrice.getCurrencyCode(), marketPrice.getPrice()); }) .collect(Collectors.toList()); } @@ -102,12 +101,13 @@ class CorePriceService { // Offer price can be null (if price feed unavailable), thus a null-tolerant comparator is used. Comparator offerPriceComparator = Comparator.comparing(Offer::getPrice, Comparator.nullsLast(Comparator.naturalOrder())); + // TODO: remove this!!! // Trading xmr-traditional is considered as buying/selling XMR, but trading xmr-crypto is // considered as buying/selling crypto. Because of this, when viewing a xmr-crypto pair, // the buy column is actually the sell column and vice versa. To maintain the expected // ordering, we have to reverse the price comparator. - boolean isCrypto = CurrencyUtil.isCryptoCurrency(currencyCode); - if (isCrypto) offerPriceComparator = offerPriceComparator.reversed(); + //boolean isCrypto = CurrencyUtil.isCryptoCurrency(currencyCode); + //if (isCrypto) offerPriceComparator = offerPriceComparator.reversed(); // Offer amounts are used for the secondary sort. They are sorted from high to low. Comparator offerAmountComparator = Comparator.comparing(Offer::getAmount).reversed(); @@ -130,11 +130,11 @@ class CorePriceService { double amount = (double) offer.getAmount().longValueExact() / LongMath.pow(10, HavenoUtils.XMR_SMALLEST_UNIT_EXPONENT); accumulatedAmount += amount; double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent()); - buyTM.put(mapPriceFeedServicePrice(priceAsDouble, currencyCode), accumulatedAmount); + buyTM.put(priceAsDouble, accumulatedAmount); } }; - // Create buyer hashmap {key:price, value:count}, uses TreeMap to sort by key (asc) + // Create seller hashmap {key:price, value:count}, uses TreeMap to sort by key (asc) accumulatedAmount = 0; LinkedHashMap sellTM = new LinkedHashMap(); for(Offer offer: sellOffers){ @@ -143,7 +143,7 @@ class CorePriceService { double amount = (double) offer.getAmount().longValueExact() / LongMath.pow(10, HavenoUtils.XMR_SMALLEST_UNIT_EXPONENT); accumulatedAmount += amount; double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent()); - sellTM.put(mapPriceFeedServicePrice(priceAsDouble, currencyCode), accumulatedAmount); + sellTM.put(priceAsDouble, accumulatedAmount); } }; @@ -157,20 +157,5 @@ class CorePriceService { return new MarketDepthInfo(currencyCode, buyPrices, buyDepth, sellPrices, sellDepth); } - - /** - * PriceProvider returns different values for crypto and traditional, - * e.g. 1 XMR = X USD - * but 1 DOGE = X XMR - * Here we convert all to: - * 1 XMR = X (FIAT or CRYPTO) - */ - private double mapPriceFeedServicePrice(double price, String currencyCode) { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - return price; - } - return price == 0 ? 0 : 1 / price; - // TODO PriceProvider.getAll() could provide these values directly when the original values are not needed for the 'desktop' UI anymore - } } diff --git a/core/src/main/java/haveno/core/api/CoreTradesService.java b/core/src/main/java/haveno/core/api/CoreTradesService.java index 177571d0d3..bd3b1cc3ad 100644 --- a/core/src/main/java/haveno/core/api/CoreTradesService.java +++ b/core/src/main/java/haveno/core/api/CoreTradesService.java @@ -123,7 +123,7 @@ class CoreTradesService { BigInteger amount = amountAsLong == 0 ? offer.getAmount() : BigInteger.valueOf(amountAsLong); // adjust amount for fixed-price offer (based on TakeOfferViewModel) - String currencyCode = offer.getCurrencyCode(); + String currencyCode = offer.getCounterCurrencyCode(); OfferDirection direction = offer.getOfferPayload().getDirection(); BigInteger maxAmount = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction, offer.hasBuyerAsTakerWithoutDeposit()); if (offer.getPrice() != null) { diff --git a/core/src/main/java/haveno/core/api/model/OfferInfo.java b/core/src/main/java/haveno/core/api/model/OfferInfo.java index 76de24401a..5de9aa84a3 100644 --- a/core/src/main/java/haveno/core/api/model/OfferInfo.java +++ b/core/src/main/java/haveno/core/api/model/OfferInfo.java @@ -129,7 +129,7 @@ public class OfferInfo implements Payload { public static OfferInfo toMyOfferInfo(OpenOffer openOffer) { // An OpenOffer is always my offer. var offer = openOffer.getOffer(); - var currencyCode = offer.getCurrencyCode(); + var currencyCode = offer.getCounterCurrencyCode(); var isActivated = !openOffer.isDeactivated(); Optional optionalTriggerPrice = openOffer.getTriggerPrice() > 0 ? Optional.of(Price.valueOf(currencyCode, openOffer.getTriggerPrice())) @@ -150,7 +150,7 @@ public class OfferInfo implements Payload { private static OfferInfoBuilder getBuilder(Offer offer) { // OfferInfo protos are passed to API client, and some field // values are converted to displayable, unambiguous form. - var currencyCode = offer.getCurrencyCode(); + var currencyCode = offer.getCounterCurrencyCode(); var preciseOfferPrice = reformatMarketPrice( requireNonNull(offer.getPrice()).toPlainString(), currencyCode); diff --git a/core/src/main/java/haveno/core/api/model/TradeInfo.java b/core/src/main/java/haveno/core/api/model/TradeInfo.java index a423bfa470..0803966ef7 100644 --- a/core/src/main/java/haveno/core/api/model/TradeInfo.java +++ b/core/src/main/java/haveno/core/api/model/TradeInfo.java @@ -57,7 +57,7 @@ public class TradeInfo implements Payload { private static final Function toPreciseTradePrice = (trade) -> reformatMarketPrice(requireNonNull(trade.getPrice()).toPlainString(), - trade.getOffer().getCurrencyCode()); + trade.getOffer().getCounterCurrencyCode()); // Haveno v1 trade protocol fields (some are in common with the BSQ Swap protocol). private final OfferInfo offer; diff --git a/core/src/main/java/haveno/core/locale/CurrencyUtil.java b/core/src/main/java/haveno/core/locale/CurrencyUtil.java index 09783b7580..25605ab18a 100644 --- a/core/src/main/java/haveno/core/locale/CurrencyUtil.java +++ b/core/src/main/java/haveno/core/locale/CurrencyUtil.java @@ -284,7 +284,7 @@ public class CurrencyUtil { } /** - * We return true if it is BTC or any of our currencies available in the assetRegistry. + * We return true if it is XMR or any of our currencies available in the assetRegistry. * For removed assets it would fail as they are not found but we don't want to conclude that they are traditional then. * As the caller might not deal with the case that a currency can be neither a cryptoCurrency nor Traditional if not found * we return true as well in case we have no traditional currency for the code. @@ -514,17 +514,11 @@ public class CurrencyUtil { } public static String getCurrencyPair(String currencyCode) { - if (isTraditionalCurrency(currencyCode)) - return Res.getBaseCurrencyCode() + "/" + currencyCode; - else - return currencyCode + "/" + Res.getBaseCurrencyCode(); + return Res.getBaseCurrencyCode() + "/" + currencyCode; } public static String getCounterCurrency(String currencyCode) { - if (isTraditionalCurrency(currencyCode)) - return currencyCode; - else - return Res.getBaseCurrencyCode(); + return currencyCode; } public static String getPriceWithCurrencyCode(String currencyCode) { @@ -532,10 +526,7 @@ public class CurrencyUtil { } public static String getPriceWithCurrencyCode(String currencyCode, String translationKey) { - if (isCryptoCurrency(currencyCode)) - return Res.get(translationKey, Res.getBaseCurrencyCode(), currencyCode); - else - return Res.get(translationKey, currencyCode, Res.getBaseCurrencyCode()); + return Res.get(translationKey, currencyCode, Res.getBaseCurrencyCode()); } public static String getOfferVolumeCode(String currencyCode) { diff --git a/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java b/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java index 0e4777488a..257d80b515 100644 --- a/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java +++ b/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java @@ -32,7 +32,7 @@ public class CryptoExchangeRate { */ public final Coin coin; - public final CryptoMoney crypto; + public final CryptoMoney cryptoMoney; /** * Construct exchange rate. This amount of coin is worth that amount of crypto. @@ -43,7 +43,7 @@ public class CryptoExchangeRate { checkArgument(crypto.isPositive()); checkArgument(crypto.currencyCode != null, "currency code required"); this.coin = coin; - this.crypto = crypto; + this.cryptoMoney = crypto; } /** @@ -59,13 +59,13 @@ public class CryptoExchangeRate { * @throws ArithmeticException if the converted crypto amount is too high or too low. */ public CryptoMoney coinToCrypto(Coin convertCoin) { - BigInteger converted = BigInteger.valueOf(coin.value) - .multiply(BigInteger.valueOf(convertCoin.value)) - .divide(BigInteger.valueOf(crypto.value)); + final BigInteger converted = BigInteger.valueOf(convertCoin.value) + .multiply(BigInteger.valueOf(cryptoMoney.value)) + .divide(BigInteger.valueOf(coin.value)); if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 || converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) throw new ArithmeticException("Overflow"); - return CryptoMoney.valueOf(crypto.currencyCode, converted.longValue()); + return CryptoMoney.valueOf(cryptoMoney.currencyCode, converted.longValue()); } /** @@ -74,12 +74,11 @@ public class CryptoExchangeRate { * @throws ArithmeticException if the converted coin amount is too high or too low. */ public Coin cryptoToCoin(CryptoMoney convertCrypto) { - checkArgument(convertCrypto.currencyCode.equals(crypto.currencyCode), "Currency mismatch: %s vs %s", - convertCrypto.currencyCode, crypto.currencyCode); + checkArgument(convertCrypto.currencyCode.equals(cryptoMoney.currencyCode), "Currency mismatch: %s vs %s", + convertCrypto.currencyCode, cryptoMoney.currencyCode); // Use BigInteger because it's much easier to maintain full precision without overflowing. - BigInteger converted = BigInteger.valueOf(crypto.value) - .multiply(BigInteger.valueOf(convertCrypto.value)) - .divide(BigInteger.valueOf(coin.value)); + final BigInteger converted = BigInteger.valueOf(convertCrypto.value).multiply(BigInteger.valueOf(coin.value)) + .divide(BigInteger.valueOf(cryptoMoney.value)); if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 || converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) throw new ArithmeticException("Overflow"); diff --git a/core/src/main/java/haveno/core/monetary/Price.java b/core/src/main/java/haveno/core/monetary/Price.java index 8dccd0608d..2ea1481ee8 100644 --- a/core/src/main/java/haveno/core/monetary/Price.java +++ b/core/src/main/java/haveno/core/monetary/Price.java @@ -136,7 +136,7 @@ public class Price extends MonetaryWrapper implements Comparable { public String toFriendlyString() { return monetary instanceof CryptoMoney ? - ((CryptoMoney) monetary).toFriendlyString() + "/XMR" : + ((CryptoMoney) monetary).toFriendlyString().replace(((CryptoMoney) monetary).currencyCode, "") + "XMR/" + ((CryptoMoney) monetary).currencyCode : ((TraditionalMoney) monetary).toFriendlyString().replace(((TraditionalMoney) monetary).currencyCode, "") + "XMR/" + ((TraditionalMoney) monetary).currencyCode; } diff --git a/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java b/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java index 976d3fa2ec..48f1eb20d5 100644 --- a/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java +++ b/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java @@ -15,84 +15,84 @@ * along with Bisq. If not, see . */ - package haveno.core.monetary; +package haveno.core.monetary; - import static com.google.common.base.Preconditions.checkArgument; - - import java.io.Serializable; - import java.math.BigInteger; - - import org.bitcoinj.core.Coin; - - import com.google.common.base.Objects; - - /** - * An exchange rate is expressed as a ratio of a {@link Coin} and a traditional money amount. - */ - public class TraditionalExchangeRate implements Serializable { - - public final Coin coin; - public final TraditionalMoney traditionalMoney; - - /** Construct exchange rate. This amount of coin is worth that amount of money. */ - public TraditionalExchangeRate(Coin coin, TraditionalMoney traditionalMoney) { - checkArgument(coin.isPositive()); - checkArgument(traditionalMoney.isPositive()); - checkArgument(traditionalMoney.currencyCode != null, "currency code required"); - this.coin = coin; - this.traditionalMoney = traditionalMoney; - } - - /** Construct exchange rate. One coin is worth this amount of traditional money. */ - public TraditionalExchangeRate(TraditionalMoney traditionalMoney) { - this(Coin.COIN, traditionalMoney); - } - - /** - * Convert a coin amount to a traditional money amount using this exchange rate. - * @throws ArithmeticException if the converted amount is too high or too low. - */ - public TraditionalMoney coinToTraditionalMoney(Coin convertCoin) { - // Use BigInteger because it's much easier to maintain full precision without overflowing. - final BigInteger converted = BigInteger.valueOf(convertCoin.value).multiply(BigInteger.valueOf(traditionalMoney.value)) - .divide(BigInteger.valueOf(coin.value)); - if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 - || converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) - throw new ArithmeticException("Overflow"); - return TraditionalMoney.valueOf(traditionalMoney.currencyCode, converted.longValue()); - } - - /** - * Convert a traditional money amount to a coin amount using this exchange rate. - * @throws ArithmeticException if the converted coin amount is too high or too low. - */ - public Coin traditionalMoneyToCoin(TraditionalMoney convertTraditionalMoney) { - checkArgument(convertTraditionalMoney.currencyCode.equals(traditionalMoney.currencyCode), "Currency mismatch: %s vs %s", - convertTraditionalMoney.currencyCode, traditionalMoney.currencyCode); - // Use BigInteger because it's much easier to maintain full precision without overflowing. - final BigInteger converted = BigInteger.valueOf(convertTraditionalMoney.value).multiply(BigInteger.valueOf(coin.value)) - .divide(BigInteger.valueOf(traditionalMoney.value)); - if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 - || converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) - throw new ArithmeticException("Overflow"); - try { - return Coin.valueOf(converted.longValue()); - } catch (IllegalArgumentException x) { - throw new ArithmeticException("Overflow: " + x.getMessage()); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TraditionalExchangeRate other = (TraditionalExchangeRate) o; - return Objects.equal(this.coin, other.coin) && Objects.equal(this.traditionalMoney, other.traditionalMoney); - } - - @Override - public int hashCode() { - return Objects.hashCode(coin, traditionalMoney); - } - } - \ No newline at end of file +import static com.google.common.base.Preconditions.checkArgument; + +import java.io.Serializable; +import java.math.BigInteger; + +import org.bitcoinj.core.Coin; + +import com.google.common.base.Objects; + +/** + * An exchange rate is expressed as a ratio of a {@link Coin} and a traditional money amount. +*/ +public class TraditionalExchangeRate implements Serializable { + + public final Coin coin; + public final TraditionalMoney traditionalMoney; + + /** Construct exchange rate. This amount of coin is worth that amount of money. */ + public TraditionalExchangeRate(Coin coin, TraditionalMoney traditionalMoney) { + checkArgument(coin.isPositive()); + checkArgument(traditionalMoney.isPositive()); + checkArgument(traditionalMoney.currencyCode != null, "currency code required"); + this.coin = coin; + this.traditionalMoney = traditionalMoney; + } + + /** Construct exchange rate. One coin is worth this amount of traditional money. */ + public TraditionalExchangeRate(TraditionalMoney traditionalMoney) { + this(Coin.COIN, traditionalMoney); + } + + /** + * Convert a coin amount to a traditional money amount using this exchange rate. + * @throws ArithmeticException if the converted amount is too high or too low. + */ + public TraditionalMoney coinToTraditionalMoney(Coin convertCoin) { + // Use BigInteger because it's much easier to maintain full precision without overflowing. + final BigInteger converted = BigInteger.valueOf(convertCoin.value) + .multiply(BigInteger.valueOf(traditionalMoney.value)) + .divide(BigInteger.valueOf(coin.value)); + if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 + || converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) + throw new ArithmeticException("Overflow"); + return TraditionalMoney.valueOf(traditionalMoney.currencyCode, converted.longValue()); + } + + /** + * Convert a traditional money amount to a coin amount using this exchange rate. + * @throws ArithmeticException if the converted coin amount is too high or too low. + */ + public Coin traditionalMoneyToCoin(TraditionalMoney convertTraditionalMoney) { + checkArgument(convertTraditionalMoney.currencyCode.equals(traditionalMoney.currencyCode), "Currency mismatch: %s vs %s", + convertTraditionalMoney.currencyCode, traditionalMoney.currencyCode); + // Use BigInteger because it's much easier to maintain full precision without overflowing. + final BigInteger converted = BigInteger.valueOf(convertTraditionalMoney.value).multiply(BigInteger.valueOf(coin.value)) + .divide(BigInteger.valueOf(traditionalMoney.value)); + if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 + || converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) + throw new ArithmeticException("Overflow"); + try { + return Coin.valueOf(converted.longValue()); + } catch (IllegalArgumentException x) { + throw new ArithmeticException("Overflow: " + x.getMessage()); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TraditionalExchangeRate other = (TraditionalExchangeRate) o; + return Objects.equal(this.coin, other.coin) && Objects.equal(this.traditionalMoney, other.traditionalMoney); + } + + @Override + public int hashCode() { + return Objects.hashCode(coin, traditionalMoney); + } +} diff --git a/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java b/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java index af2434dd22..bb29a2e678 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java +++ b/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java @@ -110,13 +110,12 @@ public class MarketAlerts { } private void onOfferAdded(Offer offer) { - String currencyCode = offer.getCurrencyCode(); + String currencyCode = offer.getCounterCurrencyCode(); MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); Price offerPrice = offer.getPrice(); if (marketPrice != null && offerPrice != null) { boolean isSellOffer = offer.getDirection() == OfferDirection.SELL; String shortOfferId = offer.getShortId(); - boolean isTraditionalCurrency = CurrencyUtil.isTraditionalCurrency(currencyCode); String alertId = getAlertId(offer); user.getMarketAlertFilters().stream() .filter(marketAlertFilter -> !offer.isMyOffer(keyRing)) @@ -133,9 +132,7 @@ public class MarketAlerts { double offerPriceValue = offerPrice.getValue(); double ratio = offerPriceValue / marketPriceAsDouble; ratio = 1 - ratio; - if (isTraditionalCurrency && isSellOffer) - ratio *= -1; - else if (!isTraditionalCurrency && !isSellOffer) + if (isSellOffer) ratio *= -1; ratio = ratio * 10000; @@ -148,26 +145,14 @@ public class MarketAlerts { if (isTriggerForBuyOfferAndTriggered || isTriggerForSellOfferAndTriggered) { String direction = isSellOffer ? Res.get("shared.sell") : Res.get("shared.buy"); String marketDir; - if (isTraditionalCurrency) { - if (isSellOffer) { - marketDir = ratio > 0 ? - Res.get("account.notifications.marketAlert.message.msg.above") : - Res.get("account.notifications.marketAlert.message.msg.below"); - } else { - marketDir = ratio < 0 ? - Res.get("account.notifications.marketAlert.message.msg.above") : - Res.get("account.notifications.marketAlert.message.msg.below"); - } + if (isSellOffer) { + marketDir = ratio > 0 ? + Res.get("account.notifications.marketAlert.message.msg.above") : + Res.get("account.notifications.marketAlert.message.msg.below"); } else { - if (isSellOffer) { - marketDir = ratio < 0 ? - Res.get("account.notifications.marketAlert.message.msg.above") : - Res.get("account.notifications.marketAlert.message.msg.below"); - } else { - marketDir = ratio > 0 ? - Res.get("account.notifications.marketAlert.message.msg.above") : - Res.get("account.notifications.marketAlert.message.msg.below"); - } + marketDir = ratio < 0 ? + Res.get("account.notifications.marketAlert.message.msg.above") : + Res.get("account.notifications.marketAlert.message.msg.below"); } ratio = Math.abs(ratio); diff --git a/core/src/main/java/haveno/core/offer/CreateOfferService.java b/core/src/main/java/haveno/core/offer/CreateOfferService.java index a41b0c5c2d..0d6824c231 100644 --- a/core/src/main/java/haveno/core/offer/CreateOfferService.java +++ b/core/src/main/java/haveno/core/offer/CreateOfferService.java @@ -22,7 +22,6 @@ import com.google.inject.Singleton; import haveno.common.app.Version; import haveno.common.crypto.PubKeyRingProvider; import haveno.common.util.Utilities; -import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; import haveno.core.monetary.Price; import haveno.core.payment.PaymentAccount; @@ -176,9 +175,8 @@ public class CreateOfferService { double marketPriceMarginParam = useMarketBasedPriceValue ? marketPriceMargin : 0; long amountAsLong = amount != null ? amount.longValueExact() : 0L; long minAmountAsLong = minAmount != null ? minAmount.longValueExact() : 0L; - boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode); - String baseCurrencyCode = isCryptoCurrency ? currencyCode : Res.getBaseCurrencyCode(); - String counterCurrencyCode = isCryptoCurrency ? Res.getBaseCurrencyCode() : currencyCode; + String baseCurrencyCode = Res.getBaseCurrencyCode(); + String counterCurrencyCode = currencyCode; String countryCode = PaymentAccountUtil.getCountryCode(paymentAccount); List acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount); String bankId = PaymentAccountUtil.getBankId(paymentAccount); diff --git a/core/src/main/java/haveno/core/offer/Offer.java b/core/src/main/java/haveno/core/offer/Offer.java index 4ddcaa21a5..2d6c4549ff 100644 --- a/core/src/main/java/haveno/core/offer/Offer.java +++ b/core/src/main/java/haveno/core/offer/Offer.java @@ -39,6 +39,7 @@ import haveno.core.payment.payload.PaymentMethod; import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.PriceFeedService; import haveno.core.trade.HavenoUtils; +import haveno.core.util.PriceUtil; import haveno.core.util.VolumeUtil; import haveno.core.util.coin.CoinUtil; import haveno.network.p2p.NodeAddress; @@ -174,32 +175,27 @@ public class Offer implements NetworkPayload, PersistablePayload { @Nullable public Price getPrice() { - String currencyCode = getCurrencyCode(); + String counterCurrencyCode = getCounterCurrencyCode(); if (!offerPayload.isUseMarketBasedPrice()) { - return Price.valueOf(currencyCode, offerPayload.getPrice()); + return Price.valueOf(counterCurrencyCode, isInverted() ? PriceUtil.invertLongPrice(offerPayload.getPrice(), counterCurrencyCode) : offerPayload.getPrice()); } checkNotNull(priceFeedService, "priceFeed must not be null"); - MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); + MarketPrice marketPrice = priceFeedService.getMarketPrice(counterCurrencyCode); if (marketPrice != null && marketPrice.isRecentExternalPriceAvailable()) { double factor; double marketPriceMargin = offerPayload.getMarketPriceMarginPct(); - if (CurrencyUtil.isCryptoCurrency(currencyCode)) { - factor = getDirection() == OfferDirection.SELL ? - 1 - marketPriceMargin : 1 + marketPriceMargin; - } else { - factor = getDirection() == OfferDirection.BUY ? - 1 - marketPriceMargin : 1 + marketPriceMargin; - } + factor = getDirection() == OfferDirection.BUY ? + 1 - marketPriceMargin : 1 + marketPriceMargin; double marketPriceAsDouble = marketPrice.getPrice(); double targetPriceAsDouble = marketPriceAsDouble * factor; try { - int precision = CurrencyUtil.isTraditionalCurrency(currencyCode) ? + int precision = CurrencyUtil.isTraditionalCurrency(counterCurrencyCode) ? TraditionalMoney.SMALLEST_UNIT_EXPONENT : CryptoMoney.SMALLEST_UNIT_EXPONENT; double scaled = MathUtils.scaleUpByPowerOf10(targetPriceAsDouble, precision); final long roundedToLong = MathUtils.roundDoubleToLong(scaled); - return Price.valueOf(currencyCode, roundedToLong); + return Price.valueOf(counterCurrencyCode, roundedToLong); } catch (Exception e) { log.error("Exception at getPrice / parseToFiat: " + e + "\n" + "That case should never happen."); @@ -225,7 +221,7 @@ public class Offer implements NetworkPayload, PersistablePayload { return; } - Price tradePrice = Price.valueOf(getCurrencyCode(), price); + Price tradePrice = Price.valueOf(getCounterCurrencyCode(), price); Price offerPrice = getPrice(); if (offerPrice == null) throw new MarketPriceNotAvailableException("Market price required for calculating trade price is not available."); @@ -240,7 +236,7 @@ public class Offer implements NetworkPayload, PersistablePayload { double deviation = Math.abs(1 - relation); log.info("Price at take-offer time: id={}, currency={}, takersPrice={}, makersPrice={}, deviation={}", - getShortId(), getCurrencyCode(), price, offerPrice.getValue(), + getShortId(), getCounterCurrencyCode(), price, offerPrice.getValue(), deviation * 100 + "%"); if (deviation > PRICE_TOLERANCE) { String msg = "Taker's trade price is too far away from our calculated price based on the market price.\n" + @@ -509,23 +505,18 @@ public class Offer implements NetworkPayload, PersistablePayload { return offerPayload.getCountryCode(); } - public String getCurrencyCode() { - if (currencyCode != null) { - return currencyCode; - } - - currencyCode = offerPayload.getBaseCurrencyCode().equals("XMR") ? - offerPayload.getCounterCurrencyCode() : - offerPayload.getBaseCurrencyCode(); - return currencyCode; + public String getBaseCurrencyCode() { + return isInverted() ? offerPayload.getCounterCurrencyCode() : offerPayload.getBaseCurrencyCode(); // legacy offers inverted crypto } public String getCounterCurrencyCode() { - return offerPayload.getCounterCurrencyCode(); + if (currencyCode != null) return currencyCode; + currencyCode = isInverted() ? offerPayload.getBaseCurrencyCode() : offerPayload.getCounterCurrencyCode(); // legacy offers inverted crypto + return currencyCode; } - public String getBaseCurrencyCode() { - return offerPayload.getBaseCurrencyCode(); + public boolean isInverted() { + return !offerPayload.getBaseCurrencyCode().equals("XMR"); } public String getPaymentMethodId() { @@ -586,21 +577,6 @@ public class Offer implements NetworkPayload, PersistablePayload { return offerPayload.isUseReOpenAfterAutoClose(); } - public boolean isXmrAutoConf() { - if (!isXmr()) { - return false; - } - if (getExtraDataMap() == null || !getExtraDataMap().containsKey(OfferPayload.XMR_AUTO_CONF)) { - return false; - } - - return getExtraDataMap().get(OfferPayload.XMR_AUTO_CONF).equals(OfferPayload.XMR_AUTO_CONF_ENABLED_VALUE); - } - - public boolean isXmr() { - return getCurrencyCode().equals("XMR"); - } - public boolean isTraditionalOffer() { return CurrencyUtil.isTraditionalCurrency(currencyCode); } diff --git a/core/src/main/java/haveno/core/offer/OfferBookService.java b/core/src/main/java/haveno/core/offer/OfferBookService.java index 50981a8fa6..3057807b84 100644 --- a/core/src/main/java/haveno/core/offer/OfferBookService.java +++ b/core/src/main/java/haveno/core/offer/OfferBookService.java @@ -271,7 +271,7 @@ public class OfferBookService { public List getOffersByCurrency(String direction, String currencyCode) { return getOffers().stream() - .filter(o -> o.getOfferPayload().getBaseCurrencyCode().equalsIgnoreCase(currencyCode) && o.getDirection().name() == direction) + .filter(o -> o.getOfferPayload().getCounterCurrencyCode().equalsIgnoreCase(currencyCode) && o.getDirection().name() == direction) .collect(Collectors.toList()); } @@ -445,11 +445,11 @@ public class OfferBookService { // We filter the case that it is a MarketBasedPrice but the price is not available // That should only be possible if the price feed provider is not available final List offerForJsonList = getOffers().stream() - .filter(offer -> !offer.isUseMarketBasedPrice() || priceFeedService.getMarketPrice(offer.getCurrencyCode()) != null) + .filter(offer -> !offer.isUseMarketBasedPrice() || priceFeedService.getMarketPrice(offer.getCounterCurrencyCode()) != null) .map(offer -> { try { return new OfferForJson(offer.getDirection(), - offer.getCurrencyCode(), + offer.getCounterCurrencyCode(), offer.getMinAmount(), offer.getAmount(), offer.getPrice(), diff --git a/core/src/main/java/haveno/core/offer/OfferFilterService.java b/core/src/main/java/haveno/core/offer/OfferFilterService.java index 298fb51bcd..206dc4921e 100644 --- a/core/src/main/java/haveno/core/offer/OfferFilterService.java +++ b/core/src/main/java/haveno/core/offer/OfferFilterService.java @@ -162,7 +162,7 @@ public class OfferFilterService { } public boolean isCurrencyBanned(Offer offer) { - return filterManager.isCurrencyBanned(offer.getCurrencyCode()); + return filterManager.isCurrencyBanned(offer.getCounterCurrencyCode()); } public boolean isPaymentMethodBanned(Offer offer) { @@ -204,7 +204,7 @@ public class OfferFilterService { accountAgeWitnessService); long myTradeLimit = accountOptional .map(paymentAccount -> accountAgeWitnessService.getMyTradeLimit(paymentAccount, - offer.getCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit())) + offer.getCounterCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit())) .orElse(0L); long offerMinAmount = offer.getMinAmount().longValueExact(); log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ", diff --git a/core/src/main/java/haveno/core/offer/OfferForJson.java b/core/src/main/java/haveno/core/offer/OfferForJson.java index caebcdc3dd..d96e6090d6 100644 --- a/core/src/main/java/haveno/core/offer/OfferForJson.java +++ b/core/src/main/java/haveno/core/offer/OfferForJson.java @@ -100,14 +100,8 @@ public class OfferForJson { private void setDisplayStrings() { try { final Price price = getPrice(); - - if (CurrencyUtil.isCryptoCurrency(currencyCode)) { - primaryMarketDirection = direction == OfferDirection.BUY ? OfferDirection.SELL : OfferDirection.BUY; - currencyPair = currencyCode + "/" + Res.getBaseCurrencyCode(); - } else { - primaryMarketDirection = direction; - currencyPair = Res.getBaseCurrencyCode() + "/" + currencyCode; - } + primaryMarketDirection = direction; + currencyPair = Res.getBaseCurrencyCode() + "/" + currencyCode; if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { priceDisplayString = traditionalFormat.noCode().format(price.getMonetary()).toString(); @@ -116,7 +110,6 @@ public class OfferForJson { primaryMarketMinVolumeDisplayString = traditionalFormat.noCode().format(getMinVolume().getMonetary()).toString(); primaryMarketVolumeDisplayString = traditionalFormat.noCode().format(getVolume().getMonetary()).toString(); } else { - // amount and volume is inverted for json priceDisplayString = cryptoFormat.noCode().format(price.getMonetary()).toString(); primaryMarketMinAmountDisplayString = cryptoFormat.noCode().format(getMinVolume().getMonetary()).toString(); primaryMarketAmountDisplayString = cryptoFormat.noCode().format(getVolume().getMonetary()).toString(); diff --git a/core/src/main/java/haveno/core/offer/OfferUtil.java b/core/src/main/java/haveno/core/offer/OfferUtil.java index 64de6fec9e..099eb15287 100644 --- a/core/src/main/java/haveno/core/offer/OfferUtil.java +++ b/core/src/main/java/haveno/core/offer/OfferUtil.java @@ -264,11 +264,11 @@ public class OfferUtil { } public static boolean isTraditionalOffer(Offer offer) { - return offer.getBaseCurrencyCode().equals("XMR"); + return CurrencyUtil.isTraditionalCurrency(offer.getCounterCurrencyCode()); } public static boolean isCryptoOffer(Offer offer) { - return offer.getCounterCurrencyCode().equals("XMR"); + return CurrencyUtil.isCryptoCurrency(offer.getCounterCurrencyCode()); } public BigInteger getMaxTradeLimitForRelease(PaymentAccount paymentAccount, diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 6d33106b4d..7aa89a4136 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -78,6 +78,7 @@ import haveno.core.trade.statistics.TradeStatisticsManager; import haveno.core.user.Preferences; import haveno.core.user.User; import haveno.core.util.JsonUtil; +import haveno.core.util.PriceUtil; import haveno.core.util.Validator; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.BtcWalletService; @@ -638,7 +639,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe private void applyTriggerState(OpenOffer openOffer) { if (openOffer.getState() != OpenOffer.State.AVAILABLE) return; - if (TriggerPriceService.isTriggered(priceFeedService.getMarketPrice(openOffer.getOffer().getCurrencyCode()), openOffer)) { + if (TriggerPriceService.isTriggered(priceFeedService.getMarketPrice(openOffer.getOffer().getCounterCurrencyCode()), openOffer)) { openOffer.deactivate(true); } } @@ -2015,12 +2016,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe log.info("Updated the owner nodeaddress of offer id={}", originalOffer.getId()); } + long normalizedPrice = originalOffer.isInverted() ? PriceUtil.invertLongPrice(originalOfferPayload.getPrice(), originalOffer.getCounterCurrencyCode()) : originalOfferPayload.getPrice(); OfferPayload updatedPayload = new OfferPayload(originalOfferPayload.getId(), originalOfferPayload.getDate(), ownerNodeAddress, originalOfferPayload.getPubKeyRing(), originalOfferPayload.getDirection(), - originalOfferPayload.getPrice(), + normalizedPrice, originalOfferPayload.getMarketPriceMarginPct(), originalOfferPayload.isUseMarketBasedPrice(), originalOfferPayload.getAmount(), @@ -2030,8 +2032,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe originalOfferPayload.getPenaltyFeePct(), originalOfferPayload.getBuyerSecurityDepositPct(), originalOfferPayload.getSellerSecurityDepositPct(), - originalOfferPayload.getBaseCurrencyCode(), - originalOfferPayload.getCounterCurrencyCode(), + originalOffer.getBaseCurrencyCode(), + originalOffer.getCounterCurrencyCode(), originalOfferPayload.getPaymentMethodId(), originalOfferPayload.getMakerPaymentAccountId(), originalOfferPayload.getCountryCode(), @@ -2063,7 +2065,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe Offer updatedOffer = new Offer(updatedPayload); updatedOffer.setPriceFeedService(priceFeedService); - OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, originalOpenOffer.getTriggerPrice()); + long normalizedTriggerPrice = originalOffer.isInverted() ? PriceUtil.invertLongPrice(originalOpenOffer.getTriggerPrice(), originalOffer.getCounterCurrencyCode()) : originalOpenOffer.getTriggerPrice(); + OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, normalizedTriggerPrice); updatedOpenOffer.setChallenge(originalOpenOffer.getChallenge()); addOpenOffer(updatedOpenOffer); requestPersistence(); diff --git a/core/src/main/java/haveno/core/offer/TriggerPriceService.java b/core/src/main/java/haveno/core/offer/TriggerPriceService.java index 18527b774c..2b8db3d520 100644 --- a/core/src/main/java/haveno/core/offer/TriggerPriceService.java +++ b/core/src/main/java/haveno/core/offer/TriggerPriceService.java @@ -102,7 +102,7 @@ public class TriggerPriceService { return false; } - String currencyCode = openOffer.getOffer().getCurrencyCode(); + String currencyCode = openOffer.getOffer().getCounterCurrencyCode(); boolean traditionalCurrency = CurrencyUtil.isTraditionalCurrency(currencyCode); int smallestUnitExponent = traditionalCurrency ? TraditionalMoney.SMALLEST_UNIT_EXPONENT : @@ -116,15 +116,13 @@ public class TriggerPriceService { OfferDirection direction = openOffer.getOffer().getDirection(); boolean isSellOffer = direction == OfferDirection.SELL; - boolean cryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode); - boolean condition = isSellOffer && !cryptoCurrency || !isSellOffer && cryptoCurrency; - return condition ? + return isSellOffer ? marketPriceAsLong < triggerPrice : marketPriceAsLong > triggerPrice; } private void checkPriceThreshold(MarketPrice marketPrice, OpenOffer openOffer) { - String currencyCode = openOffer.getOffer().getCurrencyCode(); + String currencyCode = openOffer.getOffer().getCounterCurrencyCode(); int smallestUnitExponent = CurrencyUtil.isTraditionalCurrency(currencyCode) ? TraditionalMoney.SMALLEST_UNIT_EXPONENT : CryptoMoney.SMALLEST_UNIT_EXPONENT; @@ -162,11 +160,11 @@ public class TriggerPriceService { private void onAddedOpenOffers(List openOffers) { openOffers.forEach(openOffer -> { - String currencyCode = openOffer.getOffer().getCurrencyCode(); + String currencyCode = openOffer.getOffer().getCounterCurrencyCode(); openOffersByCurrency.putIfAbsent(currencyCode, new HashSet<>()); openOffersByCurrency.get(currencyCode).add(openOffer); - MarketPrice marketPrice = priceFeedService.getMarketPrice(openOffer.getOffer().getCurrencyCode()); + MarketPrice marketPrice = priceFeedService.getMarketPrice(openOffer.getOffer().getCounterCurrencyCode()); if (marketPrice != null) { checkPriceThreshold(marketPrice, openOffer); } @@ -175,7 +173,7 @@ public class TriggerPriceService { private void onRemovedOpenOffers(List openOffers) { openOffers.forEach(openOffer -> { - String currencyCode = openOffer.getOffer().getCurrencyCode(); + String currencyCode = openOffer.getOffer().getCounterCurrencyCode(); if (openOffersByCurrency.containsKey(currencyCode)) { Set set = openOffersByCurrency.get(currencyCode); set.remove(openOffer); diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java index bc8a274f6d..518ac787ad 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java @@ -100,7 +100,7 @@ public class ValidateOffer extends Task { PaymentAccount paymentAccount = user.getPaymentAccount(offer.getMakerPaymentAccountId()); checkArgument(paymentAccount != null, "Payment account is null. makerPaymentAccountId=" + offer.getMakerPaymentAccountId()); - long maxAmount = accountAgeWitnessService.getMyTradeLimit(user.getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection(), offer.hasBuyerAsTakerWithoutDeposit()); + long maxAmount = accountAgeWitnessService.getMyTradeLimit(user.getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCounterCurrencyCode(), offer.getDirection(), offer.hasBuyerAsTakerWithoutDeposit()); checkArgument(offer.getAmount().longValueExact() <= maxAmount, "Amount is larger than " + HavenoUtils.atomicUnitsToXmr(maxAmount) + " XMR"); checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount"); @@ -112,7 +112,7 @@ public class ValidateOffer extends Task { checkArgument(offer.getDate().getTime() > 0, "Date must not be 0. date=" + offer.getDate().toString()); - checkNotNull(offer.getCurrencyCode(), "Currency is null"); + checkNotNull(offer.getCounterCurrencyCode(), "Currency is null"); checkNotNull(offer.getDirection(), "Direction is null"); checkNotNull(offer.getId(), "Id is null"); checkNotNull(offer.getPubKeyRing(), "pubKeyRing is null"); diff --git a/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java b/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java index 49c6da12e9..3ff3da0b68 100644 --- a/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java +++ b/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java @@ -106,7 +106,7 @@ public class TakeOfferModel implements Model { calculateTotalToPay(); offer.resetState(); - priceFeedService.setCurrencyCode(offer.getCurrencyCode()); + priceFeedService.setCurrencyCode(offer.getCounterCurrencyCode()); } @Override @@ -147,7 +147,7 @@ public class TakeOfferModel implements Model { private long getMaxTradeLimit() { return accountAgeWitnessService.getMyTradeLimit(paymentAccount, - offer.getCurrencyCode(), + offer.getCounterCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()); } diff --git a/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java b/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java index 11575aeb62..0ce1038769 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java @@ -122,9 +122,9 @@ public class PaymentAccountUtil { public static boolean isAmountValidForOffer(Offer offer, PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService) { - boolean hasChargebackRisk = hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode()); + boolean hasChargebackRisk = hasChargebackRisk(offer.getPaymentMethod(), offer.getCounterCurrencyCode()); boolean hasValidAccountAgeWitness = accountAgeWitnessService.getMyTradeLimit(paymentAccount, - offer.getCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()) >= offer.getMinAmount().longValueExact(); + offer.getCounterCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()) >= offer.getMinAmount().longValueExact(); return !hasChargebackRisk || hasValidAccountAgeWitness; } diff --git a/core/src/main/java/haveno/core/payment/ReceiptPredicates.java b/core/src/main/java/haveno/core/payment/ReceiptPredicates.java index a56fa4491b..33cb5d0dd6 100644 --- a/core/src/main/java/haveno/core/payment/ReceiptPredicates.java +++ b/core/src/main/java/haveno/core/payment/ReceiptPredicates.java @@ -95,7 +95,7 @@ class ReceiptPredicates { .map(TradeCurrency::getCode) .collect(Collectors.toSet()); - return codes.contains(offer.getCurrencyCode()); + return codes.contains(offer.getCounterCurrencyCode()); } boolean isMatchingSepaOffer(Offer offer, PaymentAccount account) { diff --git a/core/src/main/java/haveno/core/provider/price/PriceFeedService.java b/core/src/main/java/haveno/core/provider/price/PriceFeedService.java index c58277792f..ef4ab94e43 100644 --- a/core/src/main/java/haveno/core/provider/price/PriceFeedService.java +++ b/core/src/main/java/haveno/core/provider/price/PriceFeedService.java @@ -296,13 +296,13 @@ public class PriceFeedService { } } - private void setHavenoMarketPrice(String currencyCode, Price price) { + private void setHavenoMarketPrice(String counterCurrencyCode, Price price) { UserThread.execute(() -> { - String currencyCodeBase = CurrencyUtil.getCurrencyCodeBase(currencyCode); + String counterCurrencyCodeBase = CurrencyUtil.getCurrencyCodeBase(counterCurrencyCode); synchronized (cache) { - if (!cache.containsKey(currencyCodeBase) || !cache.get(currencyCodeBase).isExternallyProvidedPrice()) { - cache.put(currencyCodeBase, new MarketPrice(currencyCodeBase, - MathUtils.scaleDownByPowerOf10(price.getValue(), CurrencyUtil.isCryptoCurrency(currencyCode) ? CryptoMoney.SMALLEST_UNIT_EXPONENT : TraditionalMoney.SMALLEST_UNIT_EXPONENT), + if (!cache.containsKey(counterCurrencyCodeBase) || !cache.get(counterCurrencyCodeBase).isExternallyProvidedPrice()) { + cache.put(counterCurrencyCodeBase, new MarketPrice(counterCurrencyCodeBase, + MathUtils.scaleDownByPowerOf10(price.getValue(), CurrencyUtil.isCryptoCurrency(counterCurrencyCode) ? CryptoMoney.SMALLEST_UNIT_EXPONENT : TraditionalMoney.SMALLEST_UNIT_EXPONENT), 0, false)); } @@ -371,9 +371,7 @@ public class PriceFeedService { } /** - * Returns prices for all available currencies. - * For crypto currencies the value is XMR price for 1 unit of given crypto currency (e.g. 1 DOGE = X XMR). - * For traditional currencies the value is price in the given traditional currency per 1 XMR (e.g. 1 XMR = X USD). + * Returns prices for all available currencies. The base currency is always XMR. * * TODO: instrument requestPrices() result and fault handlers instead of using CountDownLatch and timeout */ diff --git a/core/src/main/java/haveno/core/provider/price/PriceProvider.java b/core/src/main/java/haveno/core/provider/price/PriceProvider.java index 931629473a..d8a7f2bef7 100644 --- a/core/src/main/java/haveno/core/provider/price/PriceProvider.java +++ b/core/src/main/java/haveno/core/provider/price/PriceProvider.java @@ -28,6 +28,8 @@ import haveno.network.p2p.P2PService; import lombok.extern.slf4j.Slf4j; import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -63,16 +65,20 @@ public class PriceProvider extends HttpClientProvider { LinkedTreeMap treeMap = (LinkedTreeMap) obj; String baseCurrencyCode = (String) treeMap.get("baseCurrencyCode"); String counterCurrencyCode = (String) treeMap.get("counterCurrencyCode"); - String currencyCode = baseCurrencyCode.equals("XMR") ? counterCurrencyCode : baseCurrencyCode; - currencyCode = CurrencyUtil.getCurrencyCodeBase(currencyCode); + boolean isInverted = !"XMR".equalsIgnoreCase(baseCurrencyCode); + if (isInverted) { + String temp = baseCurrencyCode; + baseCurrencyCode = counterCurrencyCode; + counterCurrencyCode = temp; + } + counterCurrencyCode = CurrencyUtil.getCurrencyCodeBase(counterCurrencyCode); double price = (Double) treeMap.get("price"); - // json uses double for our timestampSec long value... + if (isInverted) price = BigDecimal.ONE.divide(BigDecimal.valueOf(price), 10, RoundingMode.HALF_UP).doubleValue(); // XMR is always base currency, so invert price if applicable long timestampSec = MathUtils.doubleToLong((Double) treeMap.get("timestampSec")); - marketPriceMap.put(currencyCode, new MarketPrice(currencyCode, price, timestampSec, true)); + marketPriceMap.put(counterCurrencyCode, new MarketPrice(counterCurrencyCode, price, timestampSec, true)); } catch (Throwable t) { log.error("Error getting all prices: {}\n", t.getMessage(), t); } - }); return marketPriceMap; } diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 7d5a928676..9772a71f7c 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -65,6 +65,7 @@ import haveno.core.trade.protocol.ProcessModelServiceProvider; import haveno.core.trade.protocol.TradeListener; import haveno.core.trade.protocol.TradePeer; import haveno.core.trade.protocol.TradeProtocol; +import haveno.core.util.PriceUtil; import haveno.core.util.VolumeUtil; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.XmrWalletBase; @@ -151,6 +152,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { private boolean restartInProgress; private Subscription protocolErrorStateSubscription; private Subscription protocolErrorHeightSubscription; + public static final String PROTOCOL_VERSION = "protocolVersion"; // key for extraDataMap in trade statistics /////////////////////////////////////////////////////////////////////////////////////////// // Enums @@ -2377,8 +2379,16 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { return isBuyer() ? getBuyer().getSecurityDeposit() : getAmount().add(getSeller().getSecurityDeposit()); } + /** + * Returns the price as XMR/QUOTE. + */ public Price getPrice() { - return Price.valueOf(offer.getCurrencyCode(), price); + boolean isInverted = getOffer().isInverted(); // return uninverted price + return Price.valueOf(offer.getCounterCurrencyCode(), isInverted ? PriceUtil.invertLongPrice(price, offer.getCounterCurrencyCode()) : price); + } + + public Price getRawPrice() { + return Price.valueOf(offer.getCounterCurrencyCode(), price); } @Nullable diff --git a/core/src/main/java/haveno/core/trade/TradeUtil.java b/core/src/main/java/haveno/core/trade/TradeUtil.java index bfebca486b..186e5410a2 100644 --- a/core/src/main/java/haveno/core/trade/TradeUtil.java +++ b/core/src/main/java/haveno/core/trade/TradeUtil.java @@ -23,7 +23,6 @@ import com.google.inject.Singleton; import haveno.common.crypto.KeyRing; import haveno.common.util.Tuple2; import static haveno.core.locale.CurrencyUtil.getCurrencyPair; -import static haveno.core.locale.CurrencyUtil.isTraditionalCurrency; import haveno.core.locale.Res; import haveno.core.offer.Offer; import static haveno.core.util.FormattingUtils.formatDurationAsWords; @@ -153,8 +152,8 @@ public class TradeUtil { return ""; checkNotNull(trade.getOffer()); - checkNotNull(trade.getOffer().getCurrencyCode()); - return getCurrencyPair(trade.getOffer().getCurrencyCode()); + checkNotNull(trade.getOffer().getCounterCurrencyCode()); + return getCurrencyPair(trade.getOffer().getCounterCurrencyCode()); } public String getPaymentMethodNameWithCountryCode(Trade trade) { @@ -180,7 +179,7 @@ public class TradeUtil { return (trade.isArbitrator() ? "Arbitrator for " : "") + // TODO: use Res.get() getRole(trade.getBuyer() == trade.getMaker(), trade.isArbitrator() ? true : trade.isMaker(), // arbitrator role in context of maker - offer.getCurrencyCode()); + offer.getCounterCurrencyCode()); } /** @@ -192,25 +191,14 @@ public class TradeUtil { * @return String describing a trader's role */ private static String getRole(boolean isBuyerMakerAndSellerTaker, boolean isMaker, String currencyCode) { - if (isTraditionalCurrency(currencyCode)) { - String baseCurrencyCode = Res.getBaseCurrencyCode(); - if (isBuyerMakerAndSellerTaker) - return isMaker - ? Res.get("formatter.asMaker", baseCurrencyCode, Res.get("shared.buyer")) - : Res.get("formatter.asTaker", baseCurrencyCode, Res.get("shared.seller")); - else - return isMaker - ? Res.get("formatter.asMaker", baseCurrencyCode, Res.get("shared.seller")) - : Res.get("formatter.asTaker", baseCurrencyCode, Res.get("shared.buyer")); - } else { - if (isBuyerMakerAndSellerTaker) - return isMaker - ? Res.get("formatter.asMaker", currencyCode, Res.get("shared.seller")) - : Res.get("formatter.asTaker", currencyCode, Res.get("shared.buyer")); - else - return isMaker - ? Res.get("formatter.asMaker", currencyCode, Res.get("shared.buyer")) - : Res.get("formatter.asTaker", currencyCode, Res.get("shared.seller")); - } + String baseCurrencyCode = Res.getBaseCurrencyCode(); + if (isBuyerMakerAndSellerTaker) + return isMaker + ? Res.get("formatter.asMaker", baseCurrencyCode, Res.get("shared.buyer")) + : Res.get("formatter.asTaker", baseCurrencyCode, Res.get("shared.seller")); + else + return isMaker + ? Res.get("formatter.asMaker", baseCurrencyCode, Res.get("shared.seller")) + : Res.get("formatter.asTaker", baseCurrencyCode, Res.get("shared.buyer")); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java index 686f17f361..d2c08da515 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java @@ -45,9 +45,9 @@ public class ApplyFilter extends TradeTask { } else if (filterManager.isOfferIdBanned(trade.getId())) { failed("Offer ID is banned.\n" + "Offer ID=" + trade.getId()); - } else if (trade.getOffer() != null && filterManager.isCurrencyBanned(trade.getOffer().getCurrencyCode())) { + } else if (trade.getOffer() != null && filterManager.isCurrencyBanned(trade.getOffer().getCounterCurrencyCode())) { failed("Currency is banned.\n" + - "Currency code=" + trade.getOffer().getCurrencyCode()); + "Currency code=" + trade.getOffer().getCounterCurrencyCode()); } else if (filterManager.isPaymentMethodBanned(checkNotNull(trade.getOffer()).getPaymentMethod())) { failed("Payment method is banned.\n" + "Payment method=" + trade.getOffer().getPaymentMethod().getId()); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java b/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java index b7d07190a8..a0efc3ceaa 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java @@ -63,7 +63,7 @@ public class VerifyPeersAccountAgeWitness extends TradeTask { // only verify traditional offer Offer offer = checkNotNull(trade.getOffer()); - if (CurrencyUtil.isCryptoCurrency(offer.getCurrencyCode())) { + if (CurrencyUtil.isCryptoCurrency(offer.getCounterCurrencyCode())) { complete(); return; } diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java index a9da2bb99e..e4d379f70d 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java @@ -28,6 +28,7 @@ import haveno.common.util.CollectionUtils; import haveno.common.util.ExtraDataMapValidator; import haveno.common.util.JsonExclude; import haveno.common.util.Utilities; +import haveno.core.locale.CurrencyUtil; import haveno.core.monetary.CryptoMoney; import haveno.core.monetary.Price; import haveno.core.monetary.Volume; @@ -35,6 +36,7 @@ import haveno.core.offer.Offer; import haveno.core.offer.OfferPayload; import haveno.core.trade.Trade; import haveno.core.util.JsonUtil; +import haveno.core.util.PriceUtil; import haveno.core.util.VolumeUtil; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.storage.payload.CapabilityRequiringPayload; @@ -67,6 +69,8 @@ import static com.google.common.base.Preconditions.checkNotNull; public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayload, PersistableNetworkPayload, CapabilityRequiringPayload, DateSortedTruncatablePayload { + private static final String VERSION_KEY = "v"; // single character key for versioning + @JsonExclude private transient static final ZoneId ZONE_ID = ZoneId.systemDefault(); @@ -94,6 +98,13 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl extraDataMap.put(OfferPayload.REFERRAL_ID, referralId); } + // Store the trade protocol version to denote that the crypto price is not inverted starting with v3. + // This can be removed in the future after all stats are expected to not be inverted, + // then only stats which are missing this field prior to then need to be uninverted. + if (!trade.getOffer().isInverted() && CurrencyUtil.isCryptoCurrency(trade.getOffer().getCounterCurrencyCode())) { + extraDataMap.put(VERSION_KEY, trade.getOffer().getOfferPayload().getProtocolVersion() + ""); + } + NodeAddress arbitratorNodeAddress = checkNotNull(trade.getArbitrator().getNodeAddress(), "Arbitrator address is null", trade.getClass().getSimpleName(), trade.getId()); // The first 4 chars are sufficient to identify an arbitrator. @@ -104,7 +115,7 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl arbitratorNodeAddress.getFullAddress(); Offer offer = checkNotNull(trade.getOffer()); - return new TradeStatistics3(offer.getCurrencyCode(), + return new TradeStatistics3(offer.getCounterCurrencyCode(), fuzzTradePriceReproducibly(trade, fuzzPricePct), fuzzTradeAmountReproducibly(trade, fuzzAmountPct), offer.getPaymentMethod().getId(), @@ -114,10 +125,10 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl } private static long fuzzTradePriceReproducibly(Trade trade, double fuzzPricePct) { - if (fuzzPricePct == 0.0) return trade.getPrice().getValue(); + if (fuzzPricePct == 0.0) return trade.getRawPrice().getValue(); long originalTimestamp = trade.getTakeOfferDate().getTime(); Random random = new Random(originalTimestamp); // pseudo random generator seeded from take offer datestamp - long exactPrice = trade.getPrice().getValue(); + long exactPrice = trade.getRawPrice().getValue(); long adjustedPrice = (long) random.nextDouble(exactPrice * (1.0 - fuzzPricePct), exactPrice * (1.0 + fuzzPricePct)); log.debug("trade {} fuzzed trade price for tradeStatistics is {}", trade.getShortId(), adjustedPrice); return adjustedPrice; @@ -209,12 +220,10 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl @Getter private final String currency; - @Getter private final long price; @Getter - private final long amount; // BTC amount + private final long amount; // XMR amount private final String paymentMethod; - // As only seller is publishing it is the sellers trade date private final long date; // Old converted trade stat objects might not have it set @@ -228,7 +237,7 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl // Hash get set in constructor from json of all the other data fields (with hash = null). @JsonExclude private final byte[] hash; - // Should be only used in emergency case if we need to add data but do not want to break backward compatibility + // Should be only used in exceptional case if we need to add data but do not want to break backward compatibility // at the P2P network storage checks. The hash of the object will be used to verify if the data is valid. Any new // field in a class would break that hash and therefore break the storage mechanism. @Nullable @@ -314,8 +323,6 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl public byte[] createHash() { // We create hash from all fields excluding hash itself. We use json as simple data serialisation. - // TradeDate is different for both peers so we ignore it for hash. ExtraDataMap is ignored as well as at - // software updates we might have different entries which would cause a different hash. return Hash.getSha256Ripemd160hash(JsonUtil.objectToJson(this).getBytes(Charsets.UTF_8)); } @@ -411,11 +418,26 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl public Price getTradePrice() { if (priceObj == null) { - priceObj = Price.valueOf(currency, price); + priceObj = Price.valueOf(currency, getNormalizedPrice()); } return priceObj; } + /** + * Returns the price as XMR/QUOTE. + * + * Note: Cannot override getPrice() because it's used for gson serialization, nor do we want expose it publicly. + */ + public long getNormalizedPrice() { + return isInverted() ? PriceUtil.invertLongPrice(price, currency) : price; + } + + private boolean isInverted() { + return CurrencyUtil.isCryptoCurrency(currency) && + (extraDataMap == null || + !extraDataMap.containsKey(VERSION_KEY)); // crypto price is inverted if missing key + } + public BigInteger getTradeAmount() { return BigInteger.valueOf(amount); } @@ -472,7 +494,8 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl public String toString() { return "TradeStatistics3{" + "\n currency='" + currency + '\'' + - ",\n price=" + price + + ",\n rawPrice=" + price + + ",\n normalizedPrice=" + getNormalizedPrice() + ",\n amount=" + amount + ",\n paymentMethod='" + paymentMethod + '\'' + ",\n date=" + date + diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java index 774726d259..c2d1294d0b 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java @@ -17,7 +17,6 @@ package haveno.core.trade.statistics; -import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; import haveno.core.monetary.Price; import haveno.core.monetary.Volume; @@ -39,7 +38,7 @@ public final class TradeStatisticsForJson { public final long tradeDate; public final String paymentMethod; - // primaryMarket fields are based on industry standard where primaryMarket is always in the focus (in the app BTC is always in the focus - will be changed in a larger refactoring once) + // primaryMarket fields are based on industry standard where primaryMarket is always in the focus (in the app XMR is always in the focus) public String currencyPair; public long primaryMarketTradePrice; @@ -49,27 +48,18 @@ public final class TradeStatisticsForJson { public TradeStatisticsForJson(TradeStatistics3 tradeStatistics) { this.currency = tradeStatistics.getCurrency(); this.paymentMethod = tradeStatistics.getPaymentMethodId(); - this.tradePrice = tradeStatistics.getPrice(); + this.tradePrice = tradeStatistics.getNormalizedPrice(); this.tradeAmount = tradeStatistics.getAmount(); this.tradeDate = tradeStatistics.getDateAsLong(); try { Price tradePrice = getPrice(); - if (CurrencyUtil.isCryptoCurrency(currency)) { - currencyPair = currency + "/" + Res.getBaseCurrencyCode(); - primaryMarketTradePrice = tradePrice.getValue(); - primaryMarketTradeAmount = getTradeVolume() != null ? - getTradeVolume().getValue() : - 0; - primaryMarketTradeVolume = getTradeAmount().longValueExact(); - } else { - currencyPair = Res.getBaseCurrencyCode() + "/" + currency; - primaryMarketTradePrice = tradePrice.getValue(); - primaryMarketTradeAmount = getTradeAmount().longValueExact(); - primaryMarketTradeVolume = getTradeVolume() != null ? - getTradeVolume().getValue() : - 0; - } + currencyPair = Res.getBaseCurrencyCode() + "/" + currency; + primaryMarketTradePrice = tradePrice.getValue(); + primaryMarketTradeAmount = getTradeAmount().longValueExact(); + primaryMarketTradeVolume = getTradeVolume() != null ? + getTradeVolume().getValue() : + 0; } catch (Throwable t) { log.error(t.getMessage()); t.printStackTrace(); diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java index 863a6a885d..9188da25d1 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java @@ -101,8 +101,8 @@ public class TradeStatisticsManager { .collect(Collectors.toSet()); - // remove duplicates in early trades due to bug - deduplicateEarlyTradeStatistics(set); + // remove duplicates in early trade stats due to bugs + removeDuplicateStats(set); synchronized (observableTradeStatisticsSet) { observableTradeStatisticsSet.addAll(set); @@ -111,7 +111,42 @@ public class TradeStatisticsManager { maybeDumpStatistics(); } - private void deduplicateEarlyTradeStatistics(Set tradeStats) { + private void removeDuplicateStats(Set tradeStats) { + removeEarlyDuplicateStats(tradeStats); + removeEarlyDuplicateStatsFuzzy(tradeStats); + } + + private void removeEarlyDuplicateStats(Set tradeStats) { + + // collect trades before September 30, 2024 + Set earlyTrades = tradeStats.stream() + .filter(e -> e.getDate().toInstant().isBefore(Instant.parse("2024-09-30T00:00:00Z"))) + .collect(Collectors.toSet()); + + // collect stats with duplicated timestamp, currency, and payment method + Set duplicates = new HashSet<>(); + Set deduplicates = new HashSet<>(); + for (TradeStatistics3 tradeStatistic : earlyTrades) { + TradeStatistics3 duplicate = findDuplicate(tradeStatistic, deduplicates); + if (duplicate == null) deduplicates.add(tradeStatistic); + else duplicates.add(tradeStatistic); + } + + // remove duplicated stats + tradeStats.removeAll(duplicates); + } + + private TradeStatistics3 findDuplicate(TradeStatistics3 tradeStatistics, Set set) { + return set.stream().filter(e -> isDuplicate(tradeStatistics, e)).findFirst().orElse(null); + } + + private boolean isDuplicate(TradeStatistics3 tradeStatistics1, TradeStatistics3 tradeStatistics2) { + if (!tradeStatistics1.getPaymentMethodId().equals(tradeStatistics2.getPaymentMethodId())) return false; + if (!tradeStatistics1.getCurrency().equals(tradeStatistics2.getCurrency())) return false; + return tradeStatistics1.getDateAsLong() == tradeStatistics2.getDateAsLong(); + } + + private void removeEarlyDuplicateStatsFuzzy(Set tradeStats) { // collect trades before August 7, 2024 Set earlyTrades = tradeStats.stream() @@ -127,7 +162,7 @@ public class TradeStatisticsManager { else duplicates.add(tradeStatistic); } - // remove duplicated trades + // remove duplicated stats tradeStats.removeAll(duplicates); } @@ -138,7 +173,7 @@ public class TradeStatisticsManager { private boolean isFuzzyDuplicate(TradeStatistics3 tradeStatistics1, TradeStatistics3 tradeStatistics2) { if (!tradeStatistics1.getPaymentMethodId().equals(tradeStatistics2.getPaymentMethodId())) return false; if (!tradeStatistics1.getCurrency().equals(tradeStatistics2.getCurrency())) return false; - if (tradeStatistics1.getPrice() != tradeStatistics2.getPrice()) return false; + if (tradeStatistics1.getNormalizedPrice() != tradeStatistics2.getNormalizedPrice()) return false; return isFuzzyDuplicateV1(tradeStatistics1, tradeStatistics2) || isFuzzyDuplicateV2(tradeStatistics1, tradeStatistics2); } diff --git a/core/src/main/java/haveno/core/util/AveragePriceUtil.java b/core/src/main/java/haveno/core/util/AveragePriceUtil.java index b548c0120f..3e30327b85 100644 --- a/core/src/main/java/haveno/core/util/AveragePriceUtil.java +++ b/core/src/main/java/haveno/core/util/AveragePriceUtil.java @@ -66,15 +66,15 @@ public class AveragePriceUtil { private static List removeOutliers(List list, double percentToTrim) { List yValues = list.stream() .filter(TradeStatistics3::isValid) - .map(e -> (double) e.getPrice()) + .map(e -> (double) e.getNormalizedPrice()) .collect(Collectors.toList()); Tuple2 tuple = InlierUtil.findInlierRange(yValues, percentToTrim, HOW_MANY_STD_DEVS_CONSTITUTE_OUTLIER); double lowerBound = tuple.first; double upperBound = tuple.second; return list.stream() - .filter(e -> e.getPrice() > lowerBound) - .filter(e -> e.getPrice() < upperBound) + .filter(e -> e.getNormalizedPrice() > lowerBound) + .filter(e -> e.getNormalizedPrice() < upperBound) .collect(Collectors.toList()); } diff --git a/core/src/main/java/haveno/core/util/PriceUtil.java b/core/src/main/java/haveno/core/util/PriceUtil.java index a91b13c85c..14065afe18 100644 --- a/core/src/main/java/haveno/core/util/PriceUtil.java +++ b/core/src/main/java/haveno/core/util/PriceUtil.java @@ -35,6 +35,9 @@ import haveno.core.util.validation.AmountValidator4Decimals; import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.MonetaryValidator; + +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Optional; import lombok.extern.slf4j.Slf4j; @@ -84,7 +87,7 @@ public class PriceUtil { } public boolean hasMarketPrice(Offer offer) { - String currencyCode = offer.getCurrencyCode(); + String currencyCode = offer.getCounterCurrencyCode(); checkNotNull(priceFeedService, "priceFeed must not be null"); MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); Price price = offer.getPrice(); @@ -103,7 +106,7 @@ public class PriceUtil { return Optional.empty(); } - String currencyCode = offer.getCurrencyCode(); + String currencyCode = offer.getCounterCurrencyCode(); checkNotNull(priceFeedService, "priceFeed must not be null"); MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); double marketPriceAsDouble = checkNotNull(marketPrice).getPrice(); @@ -114,7 +117,7 @@ public class PriceUtil { double marketPrice, OfferDirection direction) { // If the offer did not use % price we calculate % from current market price - String currencyCode = offer.getCurrencyCode(); + String currencyCode = offer.getCounterCurrencyCode(); Price price = offer.getPrice(); int precision = CurrencyUtil.isTraditionalCurrency(currencyCode) ? TraditionalMoney.SMALLEST_UNIT_EXPONENT : @@ -123,29 +126,15 @@ public class PriceUtil { double scaled = MathUtils.scaleDownByPowerOf10(priceAsLong, precision); double value; if (direction == OfferDirection.SELL) { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - if (marketPrice == 0) { - return Optional.empty(); - } - value = 1 - scaled / marketPrice; - } else { - if (marketPrice == 1) { - return Optional.empty(); - } - value = scaled / marketPrice - 1; + if (marketPrice == 0) { + return Optional.empty(); } + value = 1 - scaled / marketPrice; } else { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - if (marketPrice == 1) { - return Optional.empty(); - } - value = scaled / marketPrice - 1; - } else { - if (marketPrice == 0) { - return Optional.empty(); - } - value = 1 - scaled / marketPrice; + if (marketPrice == 1) { + return Optional.empty(); } + value = scaled / marketPrice - 1; } return Optional.of(value); } @@ -183,4 +172,13 @@ public class PriceUtil { return CurrencyUtil.isTraditionalCurrency(currencyCode) ? TraditionalMoney.SMALLEST_UNIT_EXPONENT : CryptoMoney.SMALLEST_UNIT_EXPONENT; } + + public static long invertLongPrice(long price, String currencyCode) { + if (price == 0) return 0; + int precision = CurrencyUtil.isTraditionalCurrency(currencyCode) ? TraditionalMoney.SMALLEST_UNIT_EXPONENT : CryptoMoney.SMALLEST_UNIT_EXPONENT; + double priceDouble = MathUtils.scaleDownByPowerOf10(price, precision); + double priceDoubleInverted = BigDecimal.ONE.divide(BigDecimal.valueOf(priceDouble), precision, RoundingMode.HALF_UP).doubleValue(); + double scaled = MathUtils.scaleUpByPowerOf10(priceDoubleInverted, precision); + return MathUtils.roundDoubleToLong(scaled); + } } diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 1b73ad94a6..f77eb3238f 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -474,12 +474,8 @@ createOffer.amount.prompt=Enter amount in XMR createOffer.price.prompt=Enter price createOffer.volume.prompt=Enter amount in {0} createOffer.amountPriceBox.amountDescription=Amount of XMR to {0} -createOffer.amountPriceBox.buy.amountDescriptionCrypto=Amount of XMR to sell -createOffer.amountPriceBox.sell.amountDescriptionCrypto=Amount of XMR to buy createOffer.amountPriceBox.buy.volumeDescription=Amount in {0} to spend createOffer.amountPriceBox.sell.volumeDescription=Amount in {0} to receive -createOffer.amountPriceBox.buy.volumeDescriptionCrypto=Amount in {0} to sell -createOffer.amountPriceBox.sell.volumeDescriptionCrypto=Amount in {0} to buy createOffer.amountPriceBox.minAmountDescription=Minimum amount of XMR createOffer.securityDeposit.prompt=Security deposit createOffer.fundsBox.title=Fund your offer @@ -508,8 +504,8 @@ createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} createOffer.extraInfo.invalid.tooLong=Must not exceed {0} characters. # new entries -createOffer.placeOfferButton=Review: Place offer to {0} monero -createOffer.placeOfferButtonCrypto=Review: Place offer to {0} {1} +createOffer.placeOfferButton.buy=Review: Place offer to buy XMR with {0} +createOffer.placeOfferButton.sell=Review: Place offer to sell XMR for {0} createOffer.createOfferFundWalletInfo.headline=Fund your offer # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Trade amount: {0} \n @@ -579,8 +575,8 @@ takeOffer.success.info=You can see the status of your trade at \"Portfolio/Open takeOffer.error.message=An error occurred when taking the offer.\n\n{0} # new entries -takeOffer.takeOfferButton=Review: Take offer to {0} monero -takeOffer.takeOfferButtonCrypto=Review: Take offer to {0} {1} +takeOffer.takeOfferButton.buy=Review: Take offer to buy XMR with {0} +takeOffer.takeOfferButton.sell=Review: Take offer to sell XMR for {0} takeOffer.noPriceFeedAvailable=You cannot take that offer as it uses a percentage price based on the market price but there is no price feed available. takeOffer.takeOfferFundWalletInfo.headline=Fund your trade # suppress inspection "TrailingSpacesInProperty" @@ -2008,10 +2004,10 @@ offerDetailsWindow.countryBank=Maker's country of bank offerDetailsWindow.commitment=Commitment offerDetailsWindow.agree=I agree offerDetailsWindow.tac=Terms and conditions -offerDetailsWindow.confirm.maker=Confirm: Place offer to {0} monero -offerDetailsWindow.confirm.makerCrypto=Confirm: Place offer to {0} {1} -offerDetailsWindow.confirm.taker=Confirm: Take offer to {0} monero -offerDetailsWindow.confirm.takerCrypto=Confirm: Take offer to {0} {1} +offerDetailsWindow.confirm.maker.buy=Confirm: Place offer to buy XMR with {0} +offerDetailsWindow.confirm.maker.sell=Confirm: Place offer to sell XMR for {0} +offerDetailsWindow.confirm.taker.buy=Confirm: Take offer to buy XMR with {0} +offerDetailsWindow.confirm.taker.sell=Confirm: Take offer to sell XMR for {0} offerDetailsWindow.creationDate=Creation date offerDetailsWindow.makersOnion=Maker's onion address offerDetailsWindow.challenge=Offer passphrase diff --git a/core/src/main/resources/i18n/displayStrings_cs.properties b/core/src/main/resources/i18n/displayStrings_cs.properties index c78fefe199..f3f19d7b68 100644 --- a/core/src/main/resources/i18n/displayStrings_cs.properties +++ b/core/src/main/resources/i18n/displayStrings_cs.properties @@ -457,12 +457,8 @@ createOffer.amount.prompt=Zadejte množství v XMR createOffer.price.prompt=Zadejte cenu createOffer.volume.prompt=Zadejte množství v {0} createOffer.amountPriceBox.amountDescription=Množství XMR, které chcete {0} -createOffer.amountPriceBox.buy.amountDescriptionCrypto=Množství XMR k prodeji -createOffer.amountPriceBox.sell.amountDescriptionCrypto=Množství XMR k nákupu createOffer.amountPriceBox.buy.volumeDescription=Množství {0}, které odešlete createOffer.amountPriceBox.sell.volumeDescription=Množství {0}, které přijmete -createOffer.amountPriceBox.buy.volumeDescriptionCrypto=Množství {0} k prodání -createOffer.amountPriceBox.sell.volumeDescriptionCrypto=Množství {0} k nakoupení createOffer.amountPriceBox.minAmountDescription=Minimální množství XMR createOffer.securityDeposit.prompt=Kauce createOffer.fundsBox.title=Financovat nabídku @@ -490,8 +486,8 @@ createOffer.triggerPrice.invalid.tooLow=Hodnota musí být vyšší než {0} createOffer.triggerPrice.invalid.tooHigh=Hodnota musí být nižší než {0} # new entries -createOffer.placeOfferButton=Zkontrolovat vytvoření nabídky {0} monero -createOffer.placeOfferButtonCrypto=Zkontrolovat vytvoření nabídky {0} {1} +createOffer.placeOfferButton.buy=Zkontrolovat: Vytvořit nabídku na nákup XMR za {0} +createOffer.placeOfferButton.sell=Zkontrolovat: Vytvořit nabídku na prodej XMR za {0} createOffer.createOfferFundWalletInfo.headline=Financovat nabídku # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Výše obchodu: {0}\n @@ -561,8 +557,8 @@ takeOffer.success.info=Stav vašeho obchodu můžete vidět v \"Portfolio/Otevř takeOffer.error.message=Při převzetí nabídky došlo k chybě.\n\n{0} # new entries -takeOffer.takeOfferButton=Zkontrolovat přijetí nabídky {0} monero -takeOffer.takeOfferButtonCrypto=Zkontrolovat přijetí nabídky {0} {1} +takeOffer.takeOfferButton.buy=Zkontrolovat: Přijmout nabídku na nákup XMR za {0} +takeOffer.takeOfferButton.sell=Zkontrolovat: Přijmout nabídku na prodej XMR za {0} takeOffer.noPriceFeedAvailable=Tuto nabídku nemůžete vzít, protože používá procentuální cenu založenou na tržní ceně, ale není k dispozici žádný zdroj cen. takeOffer.takeOfferFundWalletInfo.headline=Financovat obchod # suppress inspection "TrailingSpacesInProperty" @@ -1964,10 +1960,10 @@ offerDetailsWindow.countryBank=Země původu banky tvůrce offerDetailsWindow.commitment=Závazek offerDetailsWindow.agree=Souhlasím offerDetailsWindow.tac=Pravidla a podmínky -offerDetailsWindow.confirm.maker=Potvrďte: Přidat nabídku {0} monero -offerDetailsWindow.confirm.makerCrypto=Potvrďte: Přidat nabídku do {0} {1} -offerDetailsWindow.confirm.taker=Potvrďte: Přijmout nabídku {0} monero -offerDetailsWindow.confirm.takerCrypto=Potvrďte: Přijmout nabídku {0} {1} +offerDetailsWindow.confirm.maker.buy=Potvrdit: Vytvořit nabídku na nákup XMR za {0} +offerDetailsWindow.confirm.maker.sell=Potvrdit: Vytvořit nabídku na prodej XMR za {0} +offerDetailsWindow.confirm.taker.buy=Potvrdit: Přijmout nabídku na nákup XMR za {0} +offerDetailsWindow.confirm.taker.sell=Potvrdit: Přijmout nabídku na prodej XMR za {0} offerDetailsWindow.creationDate=Datum vzniku offerDetailsWindow.makersOnion=Onion adresa tvůrce offerDetailsWindow.challenge=Passphrase nabídky diff --git a/core/src/main/resources/i18n/displayStrings_de.properties b/core/src/main/resources/i18n/displayStrings_de.properties index c3dd7119ab..bb81ca16d8 100644 --- a/core/src/main/resources/i18n/displayStrings_de.properties +++ b/core/src/main/resources/i18n/displayStrings_de.properties @@ -455,7 +455,8 @@ createOffer.triggerPrice.invalid.tooLow=Wert muss höher sein als {0} createOffer.triggerPrice.invalid.tooHigh=Wert muss niedriger sein als {0} # new entries -createOffer.placeOfferButton=Überprüfung: Anbieten moneros zu {0} +createOffer.placeOfferButton.buy=Überprüfen: Angebot zum Kauf von XMR mit {0} erstellen +createOffer.placeOfferButton.sell=Überprüfen: Angebot zum Verkauf von XMR für {0} erstellen createOffer.createOfferFundWalletInfo.headline=Ihr Angebot finanzieren # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Handelsbetrag: {0} \n @@ -520,7 +521,8 @@ takeOffer.success.info=Sie können den Status Ihres Trades unter \"Portfolio/Off takeOffer.error.message=Bei der Angebotsannahme trat ein Fehler auf.\n\n{0} # new entries -takeOffer.takeOfferButton=Überprüfung: Angebot annehmen moneros zu {0} +takeOffer.takeOfferButton.buy=Überprüfen: Angebot zum Kauf von XMR mit {0} annehmen +takeOffer.takeOfferButton.sell=Überprüfen: Angebot zum Verkauf von XMR für {0} annehmen takeOffer.noPriceFeedAvailable=Sie können dieses Angebot nicht annehmen, da es auf einem Prozentsatz vom Marktpreis basiert, jedoch keiner verfügbar ist. takeOffer.takeOfferFundWalletInfo.headline=Ihren Handel finanzieren # suppress inspection "TrailingSpacesInProperty" @@ -1469,8 +1471,10 @@ offerDetailsWindow.countryBank=Land der Bank des Erstellers offerDetailsWindow.commitment=Verpflichtung offerDetailsWindow.agree=Ich stimme zu offerDetailsWindow.tac=Geschäftsbedingungen -offerDetailsWindow.confirm.maker=Bestätigen: Anbieten monero zu {0} -offerDetailsWindow.confirm.taker=Bestätigen: Angebot annehmen monero zu {0} +offerDetailsWindow.confirm.maker.buy=Bestätigen: Angebot zum Kauf von XMR mit {0} erstellen +offerDetailsWindow.confirm.maker.sell=Bestätigen: Angebot zum Verkauf von XMR für {0} erstellen +offerDetailsWindow.confirm.taker.buy=Bestätigen: Angebot zum Kauf von XMR mit {0} annehmen +offerDetailsWindow.confirm.taker.sell=Bestätigen: Angebot zum Verkauf von XMR für {0} annehmen offerDetailsWindow.creationDate=Erstellungsdatum offerDetailsWindow.makersOnion=Onion-Adresse des Erstellers offerDetailsWindow.challenge=Angebots-Passphrase diff --git a/core/src/main/resources/i18n/displayStrings_es.properties b/core/src/main/resources/i18n/displayStrings_es.properties index a6a5ff1cbd..2cb634c129 100644 --- a/core/src/main/resources/i18n/displayStrings_es.properties +++ b/core/src/main/resources/i18n/displayStrings_es.properties @@ -455,7 +455,8 @@ createOffer.triggerPrice.invalid.tooLow=El valor debe ser superior a {0} createOffer.triggerPrice.invalid.tooHigh=El valor debe ser inferior a {0} # new entries -createOffer.placeOfferButton=Revisar: Poner oferta para {0} monero +createOffer.placeOfferButton.buy=Revisar: Crear oferta para comprar XMR con {0} +createOffer.placeOfferButton.sell=Revisar: Crear oferta para vender XMR por {0} createOffer.createOfferFundWalletInfo.headline=Dote de fondos su trato. # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Cantidad a intercambiar: {0}\n @@ -520,7 +521,8 @@ takeOffer.success.info=Puede ver el estado de su intercambio en \"Portafolio/Int takeOffer.error.message=Un error ocurrió al tomar la oferta.\n\n{0} # new entries -takeOffer.takeOfferButton=Revisión: Tomar oferta a {0} monero +takeOffer.takeOfferButton.buy=Revisar: Aceptar oferta para comprar XMR con {0} +takeOffer.takeOfferButton.sell=Revisar: Aceptar oferta para vender XMR por {0} takeOffer.noPriceFeedAvailable=No puede tomar esta oferta porque utiliza un precio porcentual basado en el precio de mercado y no hay fuentes de precio disponibles. takeOffer.takeOfferFundWalletInfo.headline=Dotar de fondos su intercambio # suppress inspection "TrailingSpacesInProperty" @@ -1470,8 +1472,10 @@ offerDetailsWindow.countryBank=País del banco del creador offerDetailsWindow.commitment=Compromiso offerDetailsWindow.agree=Estoy de acuerdo offerDetailsWindow.tac=Términos y condiciones: -offerDetailsWindow.confirm.maker=Confirmar: Poner oferta para {0} monero -offerDetailsWindow.confirm.taker=Confirmar: Tomar oferta {0} monero +offerDetailsWindow.confirm.maker.buy=Confirmar: Crear oferta para comprar XMR con {0} +offerDetailsWindow.confirm.maker.sell=Confirmar: Crear oferta para vender XMR por {0} +offerDetailsWindow.confirm.taker.buy=Confirmar: Aceptar oferta para comprar XMR con {0} +offerDetailsWindow.confirm.taker.sell=Confirmar: Aceptar oferta para vender XMR por {0} offerDetailsWindow.creationDate=Fecha de creación offerDetailsWindow.makersOnion=Dirección onion del creador offerDetailsWindow.challenge=Frase de contraseña de la oferta diff --git a/core/src/main/resources/i18n/displayStrings_fa.properties b/core/src/main/resources/i18n/displayStrings_fa.properties index c5444d64ca..5b9994642a 100644 --- a/core/src/main/resources/i18n/displayStrings_fa.properties +++ b/core/src/main/resources/i18n/displayStrings_fa.properties @@ -454,7 +454,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=بررسی: پیشنهاد را برای {0} بیتکوین بگذارید +createOffer.placeOfferButton.buy=بررسی: ایجاد پیشنهاد خرید XMR با {0} +createOffer.placeOfferButton.sell=بررسی: ایجاد پیشنهاد فروش XMR به ازای {0} createOffer.createOfferFundWalletInfo.headline=پیشنهاد خود را تامین وجه نمایید # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=مقدار معامله:{0}\n @@ -519,7 +520,8 @@ takeOffer.success.info=شما می‌توانید وضعیت معامله‌ی takeOffer.error.message=هنگام قبول کردن پیشنهاد، اتفاقی رخ داده است.\n\n{0} # new entries -takeOffer.takeOfferButton=بررسی: برای {0} بیتکوین پیشنهاد بگذارید. +takeOffer.takeOfferButton.buy=بررسی: قبول پیشنهاد خرید XMR با {0} +takeOffer.takeOfferButton.sell=بررسی: قبول پیشنهاد فروش XMR به ازای {0} takeOffer.noPriceFeedAvailable=امکان پذیرفتن پیشنهاد وجود ندارد. پیشنهاد از قیمت درصدی مبتنی بر قیمت روز بازار استفاده می‌کند و قیمت‌های بازار هم‌اکنون در دسترس نیست. takeOffer.takeOfferFundWalletInfo.headline=معامله خود را تأمین وجه نمایید # suppress inspection "TrailingSpacesInProperty" @@ -1465,8 +1467,10 @@ offerDetailsWindow.countryBank=کشور بانک سفارش‌گذار offerDetailsWindow.commitment=تعهد offerDetailsWindow.agree=من موافقم offerDetailsWindow.tac=شرایط و الزامات -offerDetailsWindow.confirm.maker=تأیید: پیشنهاد را به {0} بگذارید -offerDetailsWindow.confirm.taker=تأیید: پیشنهاد را به {0} بپذیرید +offerDetailsWindow.confirm.maker.buy=تأیید: ایجاد پیشنهاد خرید XMR با {0} +offerDetailsWindow.confirm.maker.sell=تأیید: ایجاد پیشنهاد فروش XMR به ازای {0} +offerDetailsWindow.confirm.taker.buy=تأیید: قبول پیشنهاد خرید XMR با {0} +offerDetailsWindow.confirm.taker.sell=تأیید: قبول پیشنهاد فروش XMR به ازای {0} offerDetailsWindow.creationDate=تاریخ ایجاد offerDetailsWindow.makersOnion=آدرس Onion سفارش گذار offerDetailsWindow.challenge=Passphrase de l'offre diff --git a/core/src/main/resources/i18n/displayStrings_fr.properties b/core/src/main/resources/i18n/displayStrings_fr.properties index 87dc02915e..75afd88758 100644 --- a/core/src/main/resources/i18n/displayStrings_fr.properties +++ b/core/src/main/resources/i18n/displayStrings_fr.properties @@ -455,7 +455,8 @@ createOffer.triggerPrice.invalid.tooLow=La valeur doit être supérieure à {0} createOffer.triggerPrice.invalid.tooHigh=La valuer doit être inférieure à {0] # new entries -createOffer.placeOfferButton=Review: Placer un ordre de {0} monero +createOffer.placeOfferButton.buy=Vérifier : Créer une offre pour acheter XMR avec {0} +createOffer.placeOfferButton.sell=Vérifier : Créer une offre pour vendre XMR contre {0} createOffer.createOfferFundWalletInfo.headline=Financer votre ordre # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=Montant du trade: {0}\n\n @@ -520,7 +521,8 @@ takeOffer.success.info=Vous pouvez voir vos transactions dans \"Portfolio/Échan takeOffer.error.message=Une erreur s'est produite pendant l’'acceptation de l'ordre.\n\n{0} # new entries -takeOffer.takeOfferButton=Vérifier: Accepter l'ordre de {0} Monero +takeOffer.takeOfferButton.buy=Vérifier : Accepter une offre pour acheter XMR avec {0} +takeOffer.takeOfferButton.sell=Vérifier : Accepter une offre pour vendre XMR contre {0} takeOffer.noPriceFeedAvailable=Vous ne pouvez pas accepter cet ordre, car celui-ci utilise un prix en pourcentage basé sur le prix du marché, mais il n'y a pas de prix de référence de disponible. takeOffer.takeOfferFundWalletInfo.headline=Provisionner votre trade # suppress inspection "TrailingSpacesInProperty" @@ -1471,8 +1473,10 @@ offerDetailsWindow.countryBank=Pays de la banque du Maker offerDetailsWindow.commitment=Engagement offerDetailsWindow.agree=J'accepte offerDetailsWindow.tac=Conditions d'utilisation -offerDetailsWindow.confirm.maker=Confirmer: Placer un ordre de {0} monero -offerDetailsWindow.confirm.taker=Confirmer: Acceptez l'ordre de {0} monero +offerDetailsWindow.confirm.maker.buy=Confirmer : Créer une offre pour acheter XMR avec {0} +offerDetailsWindow.confirm.maker.sell=Confirmer : Créer une offre pour vendre XMR contre {0} +offerDetailsWindow.confirm.taker.buy=Confirmer : Accepter une offre pour acheter XMR avec {0} +offerDetailsWindow.confirm.taker.sell=Confirmer : Accepter une offre pour vendre XMR contre {0} offerDetailsWindow.creationDate=Date de création offerDetailsWindow.makersOnion=Adresse onion du maker offerDetailsWindow.challenge=Phrase secrète de l'offre diff --git a/core/src/main/resources/i18n/displayStrings_it.properties b/core/src/main/resources/i18n/displayStrings_it.properties index a57af5a967..6c07f58220 100644 --- a/core/src/main/resources/i18n/displayStrings_it.properties +++ b/core/src/main/resources/i18n/displayStrings_it.properties @@ -454,7 +454,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=Revisione: piazza l'offerta a {0} monero +createOffer.placeOfferButton.buy=Revisiona: Crea offerta per acquistare XMR con {0} +createOffer.placeOfferButton.sell=Revisiona: Crea offerta per vendere XMR in cambio di {0} createOffer.createOfferFundWalletInfo.headline=Finanzia la tua offerta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Importo di scambio: {0} \n @@ -519,7 +520,8 @@ takeOffer.success.info=Puoi vedere lo stato del tuo scambio su \"Portafoglio/Sca takeOffer.error.message=Si è verificato un errore durante l'accettazione dell'offerta.\n\n{0} # new entries -takeOffer.takeOfferButton=Rivedi: Accetta l'offerta per {0} monero +takeOffer.takeOfferButton.buy=Revisiona: Accetta offerta per acquistare XMR con {0} +takeOffer.takeOfferButton.sell=Revisiona: Accetta offerta per vendere XMR in cambio di {0} takeOffer.noPriceFeedAvailable=Non puoi accettare questa offerta poiché utilizza un prezzo in percentuale basato sul prezzo di mercato ma non è disponibile alcun feed di prezzi. takeOffer.takeOfferFundWalletInfo.headline=Finanzia il tuo scambio # suppress inspection "TrailingSpacesInProperty" @@ -1468,8 +1470,10 @@ offerDetailsWindow.countryBank=Paese della banca del maker offerDetailsWindow.commitment=Impegno offerDetailsWindow.agree=Accetto offerDetailsWindow.tac=Termini e condizioni -offerDetailsWindow.confirm.maker=Conferma: Piazza l'offerta a {0} monero -offerDetailsWindow.confirm.taker=Conferma: Accetta l'offerta a {0} monero +offerDetailsWindow.confirm.maker.buy=Conferma: Crea offerta per acquistare XMR con {0} +offerDetailsWindow.confirm.maker.sell=Conferma: Crea offerta per vendere XMR in cambio di {0} +offerDetailsWindow.confirm.taker.buy=Conferma: Accetta offerta per acquistare XMR con {0} +offerDetailsWindow.confirm.taker.sell=Conferma: Accetta offerta per vendere XMR in cambio di {0} offerDetailsWindow.creationDate=Data di creazione offerDetailsWindow.makersOnion=Indirizzo .onion del maker offerDetailsWindow.challenge=Passphrase dell'offerta diff --git a/core/src/main/resources/i18n/displayStrings_ja.properties b/core/src/main/resources/i18n/displayStrings_ja.properties index 0a3393a0a0..19d99dd74f 100644 --- a/core/src/main/resources/i18n/displayStrings_ja.properties +++ b/core/src/main/resources/i18n/displayStrings_ja.properties @@ -455,7 +455,8 @@ createOffer.triggerPrice.invalid.tooLow=価値は{0}より高くなければな createOffer.triggerPrice.invalid.tooHigh=価値は{0}より低くなければなりません # new entries -createOffer.placeOfferButton=再確認: ビットコインを{0}オファーを出す +createOffer.placeOfferButton.buy=確認:{0}でXMRを購入するオファーを作成 +createOffer.placeOfferButton.sell=確認:{0}でXMRを売却するオファーを作成 createOffer.createOfferFundWalletInfo.headline=あなたのオファーへ入金 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 取引額: {0}\n @@ -520,7 +521,8 @@ takeOffer.success.info=あなたのトレード状態は「ポートフォリオ takeOffer.error.message=オファーの受け入れ時にエラーが発生しました。\n\n{0} # new entries -takeOffer.takeOfferButton=再確認: ビットコインを{0}オファーを申し込む +takeOffer.takeOfferButton.buy=確認:{0}でXMRを購入するオファーを受け入れ +takeOffer.takeOfferButton.sell=確認:{0}でXMRを売却するオファーを受け入れ takeOffer.noPriceFeedAvailable=そのオファーは市場価格に基づくパーセント値を使用していますが、使用可能な価格フィードがないため、利用することはできません。 takeOffer.takeOfferFundWalletInfo.headline=あなたのオファーへ入金 # suppress inspection "TrailingSpacesInProperty" @@ -1469,8 +1471,10 @@ offerDetailsWindow.countryBank=メイカーの銀行の国名 offerDetailsWindow.commitment=約束 offerDetailsWindow.agree=同意します offerDetailsWindow.tac=取引条件 -offerDetailsWindow.confirm.maker=承認: ビットコインを{0}オファーを出す -offerDetailsWindow.confirm.taker=承認: ビットコインを{0}オファーを受ける +offerDetailsWindow.confirm.maker.buy=確定:{0}でXMRを購入するオファーを作成 +offerDetailsWindow.confirm.maker.sell=確定:{0}でXMRを売却するオファーを作成 +offerDetailsWindow.confirm.taker.buy=確定:{0}でXMRを購入するオファーを受け入れ +offerDetailsWindow.confirm.taker.sell=確定:{0}でXMRを売却するオファーを受け入れ offerDetailsWindow.creationDate=作成日 offerDetailsWindow.makersOnion=メイカーのonionアドレス offerDetailsWindow.challenge=オファーパスフレーズ diff --git a/core/src/main/resources/i18n/displayStrings_pt-br.properties b/core/src/main/resources/i18n/displayStrings_pt-br.properties index c60eed1247..d7f08fde3d 100644 --- a/core/src/main/resources/i18n/displayStrings_pt-br.properties +++ b/core/src/main/resources/i18n/displayStrings_pt-br.properties @@ -457,7 +457,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=Revisar: Criar oferta para {0} monero +createOffer.placeOfferButton.buy=Revisar: Criar oferta para comprar XMR com {0} +createOffer.placeOfferButton.sell=Revisar: Criar oferta para vender XMR por {0} createOffer.createOfferFundWalletInfo.headline=Financiar sua oferta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Quantia da negociação: {0} \n @@ -522,7 +523,8 @@ takeOffer.success.info=Você pode ver o status de sua negociação em \"Portfoli takeOffer.error.message=Ocorreu um erro ao aceitar a oferta.\n\n{0} # new entries -takeOffer.takeOfferButton=Revisar: Aceitar oferta para {0} monero +takeOffer.takeOfferButton.buy=Revisar: Aceitar oferta para comprar XMR com {0} +takeOffer.takeOfferButton.sell=Revisar: Aceitar oferta para vender XMR por {0} takeOffer.noPriceFeedAvailable=Você não pode aceitar essa oferta pois ela usa uma porcentagem do preço baseada no preço de mercado, mas o canal de preços está indisponível no momento. takeOffer.takeOfferFundWalletInfo.headline=Financiar sua negociação # suppress inspection "TrailingSpacesInProperty" @@ -1472,8 +1474,10 @@ offerDetailsWindow.countryBank=País do banco do ofertante offerDetailsWindow.commitment=Compromisso offerDetailsWindow.agree=Eu concordo offerDetailsWindow.tac=Termos e condições -offerDetailsWindow.confirm.maker=Criar oferta para {0} monero -offerDetailsWindow.confirm.taker=Confirmar: Aceitar oferta de {0} monero +offerDetailsWindow.confirm.maker.buy=Confirmar: Criar oferta para comprar XMR com {0} +offerDetailsWindow.confirm.maker.sell=Confirmar: Criar oferta para vender XMR por {0} +offerDetailsWindow.confirm.taker.buy=Confirmar: Aceitar oferta para comprar XMR com {0} +offerDetailsWindow.confirm.taker.sell=Confirmar: Aceitar oferta para vender XMR por {0} offerDetailsWindow.creationDate=Criada em offerDetailsWindow.makersOnion=Endereço onion do ofertante offerDetailsWindow.challenge=Passphrase da oferta diff --git a/core/src/main/resources/i18n/displayStrings_pt.properties b/core/src/main/resources/i18n/displayStrings_pt.properties index eade3dc2ef..14c8801df4 100644 --- a/core/src/main/resources/i18n/displayStrings_pt.properties +++ b/core/src/main/resources/i18n/displayStrings_pt.properties @@ -454,7 +454,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=Rever: Colocar oferta para {0} monero +createOffer.placeOfferButton.buy=Revisar: Criar oferta para comprar XMR com {0} +createOffer.placeOfferButton.sell=Revisar: Criar oferta para vender XMR por {0} createOffer.createOfferFundWalletInfo.headline=Financiar sua oferta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Quantia de negócio: {0} \n @@ -519,7 +520,8 @@ takeOffer.success.info=Você pode ver o estado de seu negócio em \"Portefólio/ takeOffer.error.message=Ocorreu um erro ao aceitar a oferta .\n\n{0} # new entries -takeOffer.takeOfferButton=Rever: Colocar oferta para {0} monero +takeOffer.takeOfferButton.buy=Revisar: Aceitar oferta para comprar XMR com {0} +takeOffer.takeOfferButton.sell=Revisar: Aceitar oferta para vender XMR por {0} takeOffer.noPriceFeedAvailable=Você não pode aceitar aquela oferta pois ela utiliza uma percentagem do preço baseada no preço de mercado, mas o feed de preços está indisponível no momento. takeOffer.takeOfferFundWalletInfo.headline=Financiar seu negócio # suppress inspection "TrailingSpacesInProperty" @@ -1465,8 +1467,10 @@ offerDetailsWindow.countryBank=País do banco do ofertante offerDetailsWindow.commitment=Compromisso offerDetailsWindow.agree=Eu concordo offerDetailsWindow.tac=Termos e condições -offerDetailsWindow.confirm.maker=Confirmar: Criar oferta para {0} monero -offerDetailsWindow.confirm.taker=Confirmar: Aceitar oferta de {0} monero +offerDetailsWindow.confirm.maker.buy=Confirmar: Criar oferta para comprar XMR com {0} +offerDetailsWindow.confirm.maker.sell=Confirmar: Criar oferta para vender XMR por {0} +offerDetailsWindow.confirm.taker.buy=Confirmar: Aceitar oferta para comprar XMR com {0} +offerDetailsWindow.confirm.taker.sell=Confirmar: Aceitar oferta para vender XMR por {0} offerDetailsWindow.creationDate=Data de criação offerDetailsWindow.makersOnion=Endereço onion do ofertante offerDetailsWindow.challenge=Passphrase da oferta diff --git a/core/src/main/resources/i18n/displayStrings_ru.properties b/core/src/main/resources/i18n/displayStrings_ru.properties index 6cf97b8432..95c1bb896a 100644 --- a/core/src/main/resources/i18n/displayStrings_ru.properties +++ b/core/src/main/resources/i18n/displayStrings_ru.properties @@ -454,7 +454,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=Проверка: разместить предложение {0} биткойн +createOffer.placeOfferButton.buy=Проверка: Создать предложение на покупку XMR за {0} +createOffer.placeOfferButton.sell=Проверка: Создать предложение на продажу XMR за {0} createOffer.createOfferFundWalletInfo.headline=Обеспечить своё предложение # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Сумма сделки: {0} \n @@ -519,7 +520,8 @@ takeOffer.success.info=Статус вашей сделки отображает takeOffer.error.message=Ошибка при принятии предложения:\n\n{0} # new entries -takeOffer.takeOfferButton=Проверка: принять предложение {0} биткойн +takeOffer.takeOfferButton.buy=Проверка: Принять предложение на покупку XMR за {0} +takeOffer.takeOfferButton.sell=Проверка: Принять предложение на продажу XMR за {0} takeOffer.noPriceFeedAvailable=Нельзя принять это предложение, поскольку в нем используется процентный курс на основе рыночного курса, источник которого недоступен. takeOffer.takeOfferFundWalletInfo.headline=Обеспечьте свою сделку # suppress inspection "TrailingSpacesInProperty" @@ -1466,8 +1468,10 @@ offerDetailsWindow.countryBank=Страна банка мейкера offerDetailsWindow.commitment=Обязательство offerDetailsWindow.agree=Подтверждаю offerDetailsWindow.tac=Пользовательское соглашение -offerDetailsWindow.confirm.maker=Подтвердите: разместить предложение {0} биткойн -offerDetailsWindow.confirm.taker=Подтвердите: принять предложение {0} биткойн +offerDetailsWindow.confirm.maker.buy=Подтверждение: Создать предложение на покупку XMR за {0} +offerDetailsWindow.confirm.maker.sell=Подтверждение: Создать предложение на продажу XMR за {0} +offerDetailsWindow.confirm.taker.buy=Подтверждение: Принять предложение на покупку XMR за {0} +offerDetailsWindow.confirm.taker.sell=Подтверждение: Принять предложение на продажу XMR за {0} offerDetailsWindow.creationDate=Дата создания offerDetailsWindow.makersOnion=Onion-адрес мейкера offerDetailsWindow.challenge=Пароль предложения diff --git a/core/src/main/resources/i18n/displayStrings_th.properties b/core/src/main/resources/i18n/displayStrings_th.properties index 392d0bde39..1413e30c72 100644 --- a/core/src/main/resources/i18n/displayStrings_th.properties +++ b/core/src/main/resources/i18n/displayStrings_th.properties @@ -454,7 +454,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=รีวิว: ใส่ข้อเสนอไปยัง {0} บิตคอย +createOffer.placeOfferButton.buy=ตรวจสอบ: สร้างข้อเสนอเพื่อซื้อ XMR ด้วย {0} +createOffer.placeOfferButton.sell=ตรวจสอบ: สร้างข้อเสนอเพื่อขาย XMR เป็น {0} createOffer.createOfferFundWalletInfo.headline=เงินทุนสำหรับข้อเสนอของคุณ # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- ปริมาณการซื้อขาย: {0} @@ -519,7 +520,8 @@ takeOffer.success.info=คุณสามารถดูสถานะการ takeOffer.error.message=เกิดข้อผิดพลาดขณะรับข้อเสนอ\n\n{0} # new entries -takeOffer.takeOfferButton=รีวิว: รับข้อเสนอจาก {0} monero +takeOffer.takeOfferButton.buy=ตรวจสอบ: ยอมรับข้อเสนอเพื่อซื้อ XMR ด้วย {0} +takeOffer.takeOfferButton.sell=ตรวจสอบ: ยอมรับข้อเสนอเพื่อขาย XMR เป็น {0} takeOffer.noPriceFeedAvailable=คุณไม่สามารถรับข้อเสนอดังกล่าวเนื่องจากใช้ราคาร้อยละตามราคาตลาด แต่ไม่มีฟีดราคาที่พร้อมใช้งาน takeOffer.takeOfferFundWalletInfo.headline=ทุนการซื้อขายของคุณ # suppress inspection "TrailingSpacesInProperty" @@ -1466,8 +1468,10 @@ offerDetailsWindow.countryBank=ประเทศของธนาคารข offerDetailsWindow.commitment=ข้อผูกมัด offerDetailsWindow.agree=ฉันเห็นด้วย offerDetailsWindow.tac=ข้อตกลงและเงื่อนไข -offerDetailsWindow.confirm.maker=ยืนยัน: ยื่นข้อเสนอไปยัง{0} บิทคอยน์ -offerDetailsWindow.confirm.taker=ยืนยัน: รับข้อเสนอไปยัง {0} บิทคอยน์ +offerDetailsWindow.confirm.maker.buy=ยืนยัน: สร้างข้อเสนอเพื่อซื้อ XMR ด้วย {0} +offerDetailsWindow.confirm.maker.sell=ยืนยัน: สร้างข้อเสนอเพื่อขาย XMR เป็น {0} +offerDetailsWindow.confirm.taker.buy=ยืนยัน: ยอมรับข้อเสนอเพื่อซื้อ XMR ด้วย {0} +offerDetailsWindow.confirm.taker.sell=ยืนยัน: ยอมรับข้อเสนอเพื่อขาย XMR เป็น {0} offerDetailsWindow.creationDate=วันที่สร้าง offerDetailsWindow.makersOnion=ที่อยู่ onion ของผู้สร้าง offerDetailsWindow.challenge=รหัสผ่านสำหรับข้อเสนอ diff --git a/core/src/main/resources/i18n/displayStrings_tr.properties b/core/src/main/resources/i18n/displayStrings_tr.properties index eea3d55cc1..5eee6e1ea1 100644 --- a/core/src/main/resources/i18n/displayStrings_tr.properties +++ b/core/src/main/resources/i18n/displayStrings_tr.properties @@ -455,12 +455,8 @@ createOffer.amount.prompt=XMR miktarını girin createOffer.price.prompt=Fiyatı girin createOffer.volume.prompt={0} cinsinden miktar girin createOffer.amountPriceBox.amountDescription={0} XMR miktarı -createOffer.amountPriceBox.buy.amountDescriptionCrypto=Satılacak XMR miktarı -createOffer.amountPriceBox.sell.amountDescriptionCrypto=Satın alınacak XMR miktarı createOffer.amountPriceBox.buy.volumeDescription=Harcanacak {0} miktarı createOffer.amountPriceBox.sell.volumeDescription=Alınacak {0} miktarı -createOffer.amountPriceBox.buy.volumeDescriptionCrypto=Satılacak {0} miktarı -createOffer.amountPriceBox.sell.volumeDescriptionCrypto=Satın alınacak {0} miktarı createOffer.amountPriceBox.minAmountDescription=Minimum XMR miktarı createOffer.securityDeposit.prompt=Güvenlik teminatı createOffer.fundsBox.title=Teklifinizi finanse edin @@ -488,8 +484,8 @@ createOffer.triggerPrice.invalid.tooLow=Değer {0}'den yüksek olmalıdır createOffer.triggerPrice.invalid.tooHigh=Değer {0}'den düşük olmalıdır # new entries -createOffer.placeOfferButton=Gözden Geçir: Teklif ver {0} monero -createOffer.placeOfferButtonCrypto=Gözden Geçir: Teklif ver {0} {1} +createOffer.placeOfferButton.buy=Gözden Geçir: {0} ile XMR satın almak için teklif oluştur +createOffer.placeOfferButton.sell=Gözden Geçir: {0} karşılığında XMR satmak için teklif oluştur createOffer.createOfferFundWalletInfo.headline=Teklifinizi finanse edin # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Ticaret miktarı: {0} \n @@ -559,8 +555,8 @@ takeOffer.success.info=İşleminizin durumunu \"Portföy/Açık işlemler\" kıs takeOffer.error.message=Teklif alımı sırasında bir hata oluştu.\n\n{0} # new entries -takeOffer.takeOfferButton=İncele: {0} monero için teklifi al -takeOffer.takeOfferButtonCrypto=İncele: {0} {1} için teklifi al +takeOffer.takeOfferButton.buy=Gözden Geçir: {0} ile XMR satın alma teklifini kabul et +takeOffer.takeOfferButton.sell=Gözden Geçir: {0} karşılığında XMR satma teklifini kabul et takeOffer.noPriceFeedAvailable=Bu teklifi alamazsınız çünkü piyasa fiyatına dayalı yüzdelik bir fiyat kullanıyor ancak fiyat beslemesi mevcut değil. takeOffer.takeOfferFundWalletInfo.headline=İşleminizi finanse edin # suppress inspection "TrailingSpacesInProperty" @@ -1960,10 +1956,10 @@ offerDetailsWindow.countryBank=Yapıcı'nın banka ülkesi offerDetailsWindow.commitment=Taahhüt offerDetailsWindow.agree=Kabul ediyorum offerDetailsWindow.tac=Şartlar ve koşullar -offerDetailsWindow.confirm.maker=Onayla: {0} monero teklifi yerleştir -offerDetailsWindow.confirm.makerCrypto=Onayla: {0} {1} teklifi yerleştir -offerDetailsWindow.confirm.taker=Onayla: {0} monero teklifi al -offerDetailsWindow.confirm.takerCrypto=Onayla: {0} {1} teklifi al +offerDetailsWindow.confirm.maker.buy=Onayla: {0} ile XMR satın almak için teklif oluştur +offerDetailsWindow.confirm.maker.sell=Onayla: {0} karşılığında XMR satmak için teklif oluştur +offerDetailsWindow.confirm.taker.buy=Onayla: {0} ile XMR satın alma teklifini kabul et +offerDetailsWindow.confirm.taker.sell=Onayla: {0} karşılığında XMR satma teklifini kabul et offerDetailsWindow.creationDate=Oluşturma tarihi offerDetailsWindow.makersOnion=Yapıcı'nın onion adresi offerDetailsWindow.challenge=Teklif şifresi diff --git a/core/src/main/resources/i18n/displayStrings_vi.properties b/core/src/main/resources/i18n/displayStrings_vi.properties index 06d91a6a9d..d60145e7ff 100644 --- a/core/src/main/resources/i18n/displayStrings_vi.properties +++ b/core/src/main/resources/i18n/displayStrings_vi.properties @@ -454,7 +454,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=Kiểm tra:: Đặt báo giá cho {0} monero +createOffer.placeOfferButton.buy=Xem lại: Tạo đề nghị mua XMR bằng {0} +createOffer.placeOfferButton.sell=Xem lại: Tạo đề nghị bán XMR lấy {0} createOffer.createOfferFundWalletInfo.headline=Nộp tiền cho báo giá của bạn # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Khoản tiền giao dịch: {0} \n @@ -519,7 +520,8 @@ takeOffer.success.info=Bạn có thể xem trạng thái giao dịch của bạn takeOffer.error.message=Có lỗi xảy ra khi nhận báo giá.\n\n{0} # new entries -takeOffer.takeOfferButton=Rà soát: Nhận báo giá cho {0} monero +takeOffer.takeOfferButton.buy=Xem lại: Chấp nhận đề nghị mua XMR bằng {0} +takeOffer.takeOfferButton.sell=Xem lại: Chấp nhận đề nghị bán XMR lấy {0} takeOffer.noPriceFeedAvailable=Bạn không thể nhận báo giá này do sử dụng giá phần trăm dựa trên giá thị trường nhưng không có giá cung cấp. takeOffer.takeOfferFundWalletInfo.headline=Nộp tiền cho giao dịch của bạn # suppress inspection "TrailingSpacesInProperty" @@ -1468,8 +1470,10 @@ offerDetailsWindow.countryBank=Quốc gia ngân hàng của người tạo offerDetailsWindow.commitment=Cam kết offerDetailsWindow.agree=Tôi đồng ý offerDetailsWindow.tac=Điều khoản và điều kiện -offerDetailsWindow.confirm.maker=Xác nhận: Đặt chào giá cho {0} monero -offerDetailsWindow.confirm.taker=Xác nhận: Nhận chào giáo cho {0} monero +offerDetailsWindow.confirm.maker.buy=Xác nhận: Tạo đề nghị mua XMR bằng {0} +offerDetailsWindow.confirm.maker.sell=Xác nhận: Tạo đề nghị bán XMR lấy {0} +offerDetailsWindow.confirm.taker.buy=Xác nhận: Chấp nhận đề nghị mua XMR bằng {0} +offerDetailsWindow.confirm.taker.sell=Xác nhận: Chấp nhận đề nghị bán XMR lấy {0} offerDetailsWindow.creationDate=Ngày tạo offerDetailsWindow.makersOnion=Địa chỉ onion của người tạo offerDetailsWindow.challenge=Mã bảo vệ giao dịch diff --git a/core/src/main/resources/i18n/displayStrings_zh-hans.properties b/core/src/main/resources/i18n/displayStrings_zh-hans.properties index 003292245e..227ce997c0 100644 --- a/core/src/main/resources/i18n/displayStrings_zh-hans.properties +++ b/core/src/main/resources/i18n/displayStrings_zh-hans.properties @@ -455,7 +455,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=复审:报价挂单 {0} 比特币 +createOffer.placeOfferButton.buy=审核:创建以 {0} 买入 XMR 的报价 +createOffer.placeOfferButton.sell=审核:创建以 {0} 卖出 XMR 的报价 createOffer.createOfferFundWalletInfo.headline=为您的报价充值 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 交易数量:{0}\n @@ -520,7 +521,8 @@ takeOffer.success.info=你可以在“业务/未完成交易”页面内查看 takeOffer.error.message=下单时发生了一个错误。\n\n{0} # new entries -takeOffer.takeOfferButton=复审:报价下单 {0} 比特币 +takeOffer.takeOfferButton.buy=审核:接受以 {0} 买入 XMR 的报价 +takeOffer.takeOfferButton.sell=审核:接受以 {0} 卖出 XMR 的报价 takeOffer.noPriceFeedAvailable=您不能对这笔报价下单,因为它使用交易所价格百分比定价,但是您没有获得可用的价格。 takeOffer.takeOfferFundWalletInfo.headline=为交易充值 # suppress inspection "TrailingSpacesInProperty" @@ -1470,8 +1472,10 @@ offerDetailsWindow.countryBank=卖家银行所在国家或地区 offerDetailsWindow.commitment=承诺 offerDetailsWindow.agree=我同意 offerDetailsWindow.tac=条款和条件 -offerDetailsWindow.confirm.maker=确定:发布报价 {0} 比特币 -offerDetailsWindow.confirm.taker=确定:下单买入 {0} 比特币 +offerDetailsWindow.confirm.maker.buy=确认:创建以 {0} 买入 XMR 的报价 +offerDetailsWindow.confirm.maker.sell=确认:创建以 {0} 卖出 XMR 的报价 +offerDetailsWindow.confirm.taker.buy=确认:接受以 {0} 买入 XMR 的报价 +offerDetailsWindow.confirm.taker.sell=确认:接受以 {0} 卖出 XMR 的报价 offerDetailsWindow.creationDate=创建时间 offerDetailsWindow.makersOnion=卖家的匿名地址 offerDetailsWindow.challenge=提供密码 diff --git a/core/src/main/resources/i18n/displayStrings_zh-hant.properties b/core/src/main/resources/i18n/displayStrings_zh-hant.properties index ba735ecfb5..0bb330a6b0 100644 --- a/core/src/main/resources/i18n/displayStrings_zh-hant.properties +++ b/core/src/main/resources/i18n/displayStrings_zh-hant.properties @@ -455,7 +455,8 @@ createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries -createOffer.placeOfferButton=複審:報價掛單 {0} 比特幣 +createOffer.placeOfferButton.buy=審核:建立以 {0} 買入 XMR 的報價 +createOffer.placeOfferButton.sell=審核:建立以 {0} 賣出 XMR 的報價 createOffer.createOfferFundWalletInfo.headline=為您的報價充值 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 交易數量:{0}\n @@ -520,7 +521,8 @@ takeOffer.success.info=你可以在“業務/未完成交易”頁面內查看 takeOffer.error.message=下單時發生了一個錯誤。\n\n{0} # new entries -takeOffer.takeOfferButton=複審:報價下單 {0} 比特幣 +takeOffer.takeOfferButton.buy=審核:接受以 {0} 買入 XMR 的報價 +takeOffer.takeOfferButton.sell=審核:接受以 {0} 賣出 XMR 的報價 takeOffer.noPriceFeedAvailable=您不能對這筆報價下單,因為它使用交易所價格百分比定價,但是您沒有獲得可用的價格。 takeOffer.takeOfferFundWalletInfo.headline=為交易充值 # suppress inspection "TrailingSpacesInProperty" @@ -1470,8 +1472,10 @@ offerDetailsWindow.countryBank=賣家銀行所在國家或地區 offerDetailsWindow.commitment=承諾 offerDetailsWindow.agree=我同意 offerDetailsWindow.tac=條款和條件 -offerDetailsWindow.confirm.maker=確定:發佈報價 {0} 比特幣 -offerDetailsWindow.confirm.taker=確定:下單買入 {0} 比特幣 +offerDetailsWindow.confirm.maker.buy=確認:建立以 {0} 買入 XMR 的報價 +offerDetailsWindow.confirm.maker.sell=確認:建立以 {0} 賣出 XMR 的報價 +offerDetailsWindow.confirm.taker.buy=確認:接受以 {0} 買入 XMR 的報價 +offerDetailsWindow.confirm.taker.sell=確認:接受以 {0} 賣出 XMR 的報價 offerDetailsWindow.creationDate=創建時間 offerDetailsWindow.makersOnion=賣家的匿名地址 offerDetailsWindow.challenge=提供密碼 diff --git a/core/src/test/java/haveno/core/monetary/PriceTest.java b/core/src/test/java/haveno/core/monetary/PriceTest.java index 49a32ac09d..37aa618caa 100644 --- a/core/src/test/java/haveno/core/monetary/PriceTest.java +++ b/core/src/test/java/haveno/core/monetary/PriceTest.java @@ -59,13 +59,13 @@ public class PriceTest { ); assertEquals( - "10000.2346 LTC/XMR", + "10000.2346 XMR/LTC", parse("LTC", "10000,23456789").toFriendlyString(), "Too many decimals should get rounded up properly." ); assertEquals( - "10000.2345 LTC/XMR", + "10000.2345 XMR/LTC", parse("LTC", "10000,23454999").toFriendlyString(), "Too many decimals should get rounded down properly." ); @@ -108,13 +108,13 @@ public class PriceTest { ); assertEquals( - "10000.2346 LTC/XMR", + "10000.2346 XMR/LTC", valueOf("LTC", 1000023456789L).toFriendlyString(), "Too many decimals should get rounded up properly." ); assertEquals( - "10000.2345 LTC/XMR", + "10000.2345 XMR/LTC", valueOf("LTC", 1000023454999L).toFriendlyString(), "Too many decimals should get rounded down properly." ); diff --git a/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java b/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java index 1a0243b1b8..34ad938dc1 100644 --- a/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java +++ b/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java @@ -34,7 +34,7 @@ public class ReceiptPredicatesTest { @Test public void testIsMatchingCurrency() { Offer offer = mock(Offer.class); - when(offer.getCurrencyCode()).thenReturn("USD"); + when(offer.getCounterCurrencyCode()).thenReturn("USD"); PaymentAccount account = mock(PaymentAccount.class); when(account.getTradeCurrencies()).thenReturn(Lists.newArrayList( diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java index 223b1f2874..f867721560 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java @@ -48,7 +48,6 @@ import haveno.proto.grpc.MarketPriceReply; import haveno.proto.grpc.MarketPriceRequest; import haveno.proto.grpc.MarketPricesReply; import haveno.proto.grpc.MarketPricesRequest; -import static haveno.proto.grpc.PriceGrpc.PriceImplBase; import static haveno.proto.grpc.PriceGrpc.getGetMarketPriceMethod; import haveno.proto.grpc.PriceGrpc.PriceImplBase; import io.grpc.ServerInterceptor; @@ -57,8 +56,6 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.PriceGrpc.getGetMarketPriceMethod; import static java.util.concurrent.TimeUnit.SECONDS; import lombok.extern.slf4j.Slf4j; diff --git a/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java index 6a9f1344d6..47fe298dd1 100644 --- a/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java +++ b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java @@ -198,6 +198,6 @@ public class PeerInfoIconTrading extends PeerInfoIcon { Offer offerToCheck = Trade != null ? Trade.getOffer() : offer; return offerToCheck != null && - PaymentMethod.hasChargebackRisk(offerToCheck.getPaymentMethod(), offerToCheck.getCurrencyCode()); + PaymentMethod.hasChargebackRisk(offerToCheck.getPaymentMethod(), offerToCheck.getCounterCurrencyCode()); } } diff --git a/desktop/src/main/java/haveno/desktop/main/market/MarketView.java b/desktop/src/main/java/haveno/desktop/main/market/MarketView.java index fc72de153a..b4f5c02d0a 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/MarketView.java +++ b/desktop/src/main/java/haveno/desktop/main/market/MarketView.java @@ -209,7 +209,7 @@ public class MarketView extends ActivatableView { StringBuilder sb = new StringBuilder(); sb.append("Offer ID: ").append(offer.getId()).append("\n") .append("Type: ").append(offer.getDirection().name()).append("\n") - .append("Market: ").append(CurrencyUtil.getCurrencyPair(offer.getCurrencyCode())).append("\n") + .append("Market: ").append(CurrencyUtil.getCurrencyPair(offer.getCounterCurrencyCode())).append("\n") .append("Price: ").append(FormattingUtils.formatPrice(offer.getPrice())).append("\n") .append("Amount: ").append(DisplayUtils.formatAmount(offer, formatter)).append(" BTC\n") .append("Payment method: ").append(Res.get(offer.getPaymentMethod().getId())).append("\n") diff --git a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java index 08d122ecce..163337a448 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java +++ b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java @@ -236,19 +236,19 @@ public class OfferBookChartView extends ActivatableViewAndModel model.goToOfferView(model.isCrypto() ? OfferDirection.SELL : OfferDirection.BUY)); + sellButton.setOnAction(e -> model.goToOfferView(OfferDirection.BUY)); sellButton.setId("sell-button-big"); buyHeaderLabel.setText(Res.get("market.offerBook.buyOffersHeaderLabel", viewBaseCurrencyCode)); buyButton.updateText(Res.get( "shared.buyCurrency", viewBaseCurrencyCode)); buyButton.setGraphic(GUIUtil.getCurrencyIconWithBorder(viewBaseCurrencyCode)); - buyButton.setOnAction(e -> model.goToOfferView(model.isCrypto() ? OfferDirection.BUY : OfferDirection.SELL)); + buyButton.setOnAction(e -> model.goToOfferView(OfferDirection.SELL)); buyButton.setId("buy-button-big"); priceColumnLabel.set(Res.get("shared.priceWithCur", viewPriceCurrencyCode)); @@ -358,8 +358,8 @@ public class OfferBookChartView extends ActivatableViewAndModel e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()))) + .anyMatch(e -> e.getCounterCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()))) updateChartData(); } @@ -156,7 +156,7 @@ class OfferBookChartViewModel extends ActivatableViewModel { synchronized (offerBookListItems) { List tradeCurrencyList = offerBookListItems.stream() .map(e -> { - String currencyCode = e.getOffer().getCurrencyCode(); + String currencyCode = e.getOffer().getCounterCurrencyCode(); Optional tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(currencyCode); return tradeCurrencyOptional.orElse(null); }) @@ -221,7 +221,7 @@ class OfferBookChartViewModel extends ActivatableViewModel { synchronized (offerBookListItems) { List offerList = offerBookListItems.stream() .map(OfferBookListItem::getOffer) - .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) + .filter(e -> e.getCounterCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) && e.getDirection().equals(direction)) .collect(Collectors.toList()); BigInteger sum = BigInteger.ZERO; @@ -234,7 +234,7 @@ class OfferBookChartViewModel extends ActivatableViewModel { synchronized (offerBookListItems) { List volumes = offerBookListItems.stream() .map(OfferBookListItem::getOffer) - .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) + .filter(e -> e.getCounterCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) && e.getDirection().equals(direction)) .map(Offer::getVolume) .collect(Collectors.toList()); @@ -300,13 +300,13 @@ class OfferBookChartViewModel extends ActivatableViewModel { } public int getMaxNumberOfPriceZeroDecimalsToColorize(Offer offer) { - return CurrencyUtil.isVolumeRoundedToNearestUnit(offer.getCurrencyCode()) + return CurrencyUtil.isVolumeRoundedToNearestUnit(offer.getCounterCurrencyCode()) ? GUIUtil.NUM_DECIMALS_UNIT : GUIUtil.NUM_DECIMALS_PRECISE; } public int getZeroDecimalsForPrice(Offer offer) { - return CurrencyUtil.isPricePrecise(offer.getCurrencyCode()) + return CurrencyUtil.isPricePrecise(offer.getCounterCurrencyCode()) ? GUIUtil.NUM_DECIMALS_PRECISE : GUIUtil.NUM_DECIMALS_PRICE_LESS_PRECISE; } @@ -350,13 +350,6 @@ class OfferBookChartViewModel extends ActivatableViewModel { // Offer price can be null (if price feed unavailable), thus a null-tolerant comparator is used. Comparator offerPriceComparator = Comparator.comparing(Offer::getPrice, Comparator.nullsLast(Comparator.naturalOrder())); - // Trading xmr-traditional is considered as buying/selling XMR, but trading xmr-crypto is - // considered as buying/selling Crypto. Because of this, when viewing a xmr-crypto pair, - // the buy column is actually the sell column and vice versa. To maintain the expected - // ordering, we have to reverse the price comparator. - boolean isCrypto = CurrencyUtil.isCryptoCurrency(getCurrencyCode()); -// if (isCrypto) offerPriceComparator = offerPriceComparator.reversed(); - // Offer amounts are used for the secondary sort. They are sorted from high to low. Comparator offerAmountComparator = Comparator.comparing(Offer::getAmount).reversed(); @@ -367,11 +360,11 @@ class OfferBookChartViewModel extends ActivatableViewModel { offerPriceComparator .thenComparing(offerAmountComparator); - OfferDirection buyOfferDirection = isCrypto ? OfferDirection.SELL : OfferDirection.BUY; + OfferDirection buyOfferDirection = OfferDirection.BUY; List allBuyOffers = offerBookListItems.stream() .map(OfferBookListItem::getOffer) - .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) + .filter(e -> e.getCounterCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) && e.getDirection().equals(buyOfferDirection)) .sorted(buyOfferSortComparator) .collect(Collectors.toList()); @@ -398,11 +391,11 @@ class OfferBookChartViewModel extends ActivatableViewModel { buildChartAndTableEntries(allBuyOffers, OfferDirection.BUY, buyData, topBuyOfferList); - OfferDirection sellOfferDirection = isCrypto ? OfferDirection.BUY : OfferDirection.SELL; + OfferDirection sellOfferDirection = OfferDirection.SELL; List allSellOffers = offerBookListItems.stream() .map(OfferBookListItem::getOffer) - .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) + .filter(e -> e.getCounterCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) && e.getDirection().equals(sellOfferDirection)) .sorted(sellOfferSortComparator) .collect(Collectors.toList()); diff --git a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java index 2ca1d3e743..9a2a63e51c 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java @@ -116,11 +116,11 @@ class SpreadViewModel extends ActivatableViewModel { synchronized (offerBookListItems) { for (OfferBookListItem offerBookListItem : offerBookListItems) { Offer offer = offerBookListItem.getOffer(); - String key = offer.getCurrencyCode(); + String key = offer.getCounterCurrencyCode(); if (includePaymentMethod) { key = offer.getPaymentMethod().getShortName(); if (expandedView) { - key += ":" + offer.getCurrencyCode(); + key += ":" + offer.getCounterCurrencyCode(); } } if (!offersByCurrencyMap.containsKey(key)) @@ -134,8 +134,6 @@ class SpreadViewModel extends ActivatableViewModel { for (String key : offersByCurrencyMap.keySet()) { List offers = offersByCurrencyMap.get(key); - boolean iTraditionalCurrency = (offers.size() > 0 && offers.get(0).getPaymentMethod().isTraditional()); - List uniqueOffers = offers.stream().filter(distinctByKey(Offer::getId)).collect(Collectors.toList()); List buyOffers = uniqueOffers @@ -145,11 +143,7 @@ class SpreadViewModel extends ActivatableViewModel { long a = o1.getPrice() != null ? o1.getPrice().getValue() : 0; long b = o2.getPrice() != null ? o2.getPrice().getValue() : 0; if (a != b) { - if (iTraditionalCurrency) { - return a < b ? 1 : -1; - } else { - return a < b ? -1 : 1; - } + return a < b ? 1 : -1; } return 0; }) @@ -162,11 +156,7 @@ class SpreadViewModel extends ActivatableViewModel { long a = o1.getPrice() != null ? o1.getPrice().getValue() : 0; long b = o2.getPrice() != null ? o2.getPrice().getValue() : 0; if (a != b) { - if (iTraditionalCurrency) { - return a > b ? 1 : -1; - } else { - return a > b ? -1 : 1; - } + return a > b ? 1 : -1; } return 0; }) @@ -178,24 +168,22 @@ class SpreadViewModel extends ActivatableViewModel { Price bestSellOfferPrice = sellOffers.isEmpty() ? null : sellOffers.get(0).getPrice(); Price bestBuyOfferPrice = buyOffers.isEmpty() ? null : buyOffers.get(0).getPrice(); if (bestBuyOfferPrice != null && bestSellOfferPrice != null && - sellOffers.get(0).getCurrencyCode().equals(buyOffers.get(0).getCurrencyCode())) { - MarketPrice marketPrice = priceFeedService.getMarketPrice(sellOffers.get(0).getCurrencyCode()); + sellOffers.get(0).getCounterCurrencyCode().equals(buyOffers.get(0).getCounterCurrencyCode())) { + MarketPrice marketPrice = priceFeedService.getMarketPrice(sellOffers.get(0).getCounterCurrencyCode()); // There have been some bug reports that an offer caused an overflow exception. // We never found out which offer it was. So add here a try/catch to get better info if it // happens again try { - if (iTraditionalCurrency) - spread = bestSellOfferPrice.subtract(bestBuyOfferPrice); - else - spread = bestBuyOfferPrice.subtract(bestSellOfferPrice); + spread = bestSellOfferPrice.subtract(bestBuyOfferPrice); // TODO maybe show extra columns with spread and use real amount diff // not % based. e.g. diff between best buy and sell offer (of small amounts its a smaller gain) if (spread != null && marketPrice != null && marketPrice.isPriceAvailable()) { double marketPriceAsDouble = marketPrice.getPrice(); - final double precision = iTraditionalCurrency ? + boolean isTraditionalCurrency = (offers.size() > 0 && offers.get(0).getPaymentMethod().isTraditional()); + final double precision = isTraditionalCurrency ? Math.pow(10, TraditionalMoney.SMALLEST_UNIT_EXPONENT) : Math.pow(10, CryptoMoney.SMALLEST_UNIT_EXPONENT); @@ -217,8 +205,8 @@ class SpreadViewModel extends ActivatableViewModel { "Details of offer data: \n" + "bestSellOfferPrice: " + bestSellOfferPrice.getValue() + "\n" + "bestBuyOfferPrice: " + bestBuyOfferPrice.getValue() + "\n" + - "sellOffer getCurrencyCode: " + sellOffers.get(0).getCurrencyCode() + "\n" + - "buyOffer getCurrencyCode: " + buyOffers.get(0).getCurrencyCode() + "\n\n" + + "sellOffer getCurrencyCode: " + sellOffers.get(0).getCounterCurrencyCode() + "\n" + + "buyOffer getCurrencyCode: " + buyOffers.get(0).getCounterCurrencyCode() + "\n\n" + "Please copy and paste this data and send it to the developers so they can investigate the issue."; new Popup().error(msg).show(); log.error(t.toString()); diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java b/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java index 0863ab28be..b3d8687849 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java @@ -263,16 +263,10 @@ public class ChartCalculations { Long[] prices = new Long[tradePrices.size()]; tradePrices.toArray(prices); long medianPrice = MathUtils.getMedian(prices); - boolean isBullish; - if (CurrencyUtil.isCryptoCurrency(currencyCode)) { - isBullish = close < open; - BigInteger accumulatedAmountAsBI = MathUtils.scaleUpByPowerOf10(accumulatedAmount, CryptoMoney.SMALLEST_UNIT_EXPONENT - 4); - averagePrice = MathUtils.roundDoubleToLong(HavenoUtils.divide(accumulatedAmountAsBI, accumulatedVolume)); - } else { - isBullish = close > open; - BigInteger accumulatedVolumeAsBI = MathUtils.scaleUpByPowerOf10(accumulatedVolume, TraditionalMoney.SMALLEST_UNIT_EXPONENT + 4); - averagePrice = MathUtils.roundDoubleToLong(HavenoUtils.divide(accumulatedVolumeAsBI, accumulatedAmount)); - } + boolean isBullish = close > open; + int smallestUnitExponent = CurrencyUtil.isCryptoCurrency(currencyCode) ? CryptoMoney.SMALLEST_UNIT_EXPONENT : TraditionalMoney.SMALLEST_UNIT_EXPONENT; + BigInteger accumulatedVolumeAsBI = MathUtils.scaleUpByPowerOf10(accumulatedVolume, smallestUnitExponent + 4); + averagePrice = MathUtils.roundDoubleToLong(HavenoUtils.divide(accumulatedVolumeAsBI, accumulatedAmount)); Date dateFrom = new Date(getTimeFromTickIndex(tick, itemsPerInterval)); Date dateTo = new Date(getTimeFromTickIndex(tick + 1, itemsPerInterval)); @@ -281,10 +275,10 @@ public class ChartCalculations { DisplayUtils.formatDate(dateFrom) + " - " + DisplayUtils.formatDate(dateTo); // We do not need precision, so we scale down before multiplication otherwise we could get an overflow. - averageUsdPrice = (long) MathUtils.scaleDownByPowerOf10((double) averageUsdPrice, TraditionalMoney.SMALLEST_UNIT_EXPONENT); + averageUsdPrice = (long) MathUtils.scaleDownByPowerOf10((double) averageUsdPrice, smallestUnitExponent); long volumeInUsd = averageUsdPrice * MathUtils.scaleDownByPowerOf10(accumulatedAmount, 4).longValue(); // We store USD value without decimals as its only total volume, no precision is needed. - volumeInUsd = (long) MathUtils.scaleDownByPowerOf10((double) volumeInUsd, TraditionalMoney.SMALLEST_UNIT_EXPONENT); + volumeInUsd = (long) MathUtils.scaleDownByPowerOf10((double) volumeInUsd, smallestUnitExponent); return new CandleData(tick, open, close, high, low, averagePrice, medianPrice, accumulatedAmount.longValueExact(), accumulatedVolume.longValueExact(), numTrades, isBullish, dateString, volumeInUsd); } diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java b/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java index 665f25aa3e..022c3cbdc6 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java @@ -265,7 +265,7 @@ class TradesChartsViewModel extends ActivatableViewModel { return; } if (throwable != null) { - log.error("Error at applyAsyncChartData. {}", throwable.toString()); + log.error("Error at applyAsyncChartData. {}", throwable); return; } UserThread.execute(() -> { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java index 68d585e3f5..fbaa716d2a 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java @@ -321,20 +321,12 @@ public abstract class MutableOfferView> exten if (OfferViewUtil.isShownAsBuyOffer(direction, tradeCurrency)) { placeOfferButton.setId("buy-button-big"); - if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButton", Res.get("shared.buy")); - } else { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), tradeCurrency.getCode()); - } + placeOfferButtonLabel = Res.get("createOffer.placeOfferButton.buy", tradeCurrency.getCode()); nextButton.setId("buy-button"); fundFromSavingsWalletButton.setId("buy-button"); } else { placeOfferButton.setId("sell-button-big"); - if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButton", Res.get("shared.sell")); - } else { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), tradeCurrency.getCode()); - } + placeOfferButtonLabel = Res.get("createOffer.placeOfferButton.sell", tradeCurrency.getCode()); nextButton.setId("sell-button"); fundFromSavingsWalletButton.setId("sell-button"); } @@ -736,15 +728,6 @@ public abstract class MutableOfferView> exten marketBasedPriceTextField.clear(); volumeTextField.clear(); triggerPriceInputTextField.clear(); - if (!CurrencyUtil.isTraditionalCurrency(newValue)) { - if (model.isShownAsBuyOffer()) { - placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), - model.getTradeCurrency().getCode())); - } else { - placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), - model.getTradeCurrency().getCode())); - } - } }; placeOfferCompletedListener = (o, oldValue, newValue) -> { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java index b015cabd48..1c396f202a 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java @@ -261,15 +261,11 @@ public abstract class MutableOfferViewModel ext private void addBindings() { if (dataModel.getDirection() == OfferDirection.BUY) { volumeDescriptionLabel.bind(createStringBinding( - () -> Res.get(CurrencyUtil.isTraditionalCurrency(dataModel.getTradeCurrencyCode().get()) ? - "createOffer.amountPriceBox.buy.volumeDescription" : - "createOffer.amountPriceBox.buy.volumeDescriptionCrypto", dataModel.getTradeCurrencyCode().get()), + () -> Res.get("createOffer.amountPriceBox.buy.volumeDescription", dataModel.getTradeCurrencyCode().get()), dataModel.getTradeCurrencyCode())); } else { volumeDescriptionLabel.bind(createStringBinding( - () -> Res.get(CurrencyUtil.isTraditionalCurrency(dataModel.getTradeCurrencyCode().get()) ? - "createOffer.amountPriceBox.sell.volumeDescription" : - "createOffer.amountPriceBox.sell.volumeDescriptionCrypto", dataModel.getTradeCurrencyCode().get()), + () -> Res.get("createOffer.amountPriceBox.sell.volumeDescription", dataModel.getTradeCurrencyCode().get()), dataModel.getTradeCurrencyCode())); } volumePromptLabel.bind(createStringBinding( @@ -319,7 +315,6 @@ public abstract class MutableOfferViewModel ext }; priceStringListener = (ov, oldValue, newValue) -> { updateMarketPriceAvailable(); - final String currencyCode = dataModel.getTradeCurrencyCode().get(); if (!ignorePriceStringListener) { if (isPriceInputValid(newValue).isValid) { setPriceToModel(); @@ -332,9 +327,7 @@ public abstract class MutableOfferViewModel ext try { double priceAsDouble = ParsingUtils.parseNumberStringToDouble(price.get()); double relation = priceAsDouble / marketPriceAsDouble; - final OfferDirection compareDirection = CurrencyUtil.isCryptoCurrency(currencyCode) ? - OfferDirection.SELL : - OfferDirection.BUY; + final OfferDirection compareDirection = OfferDirection.BUY; double percentage = dataModel.getDirection() == compareDirection ? 1 - relation : relation - 1; percentage = MathUtils.roundDouble(percentage, 4); dataModel.setMarketPriceMarginPct(percentage); @@ -367,9 +360,7 @@ public abstract class MutableOfferViewModel ext if (marketPrice != null && marketPrice.isRecentExternalPriceAvailable()) { percentage = MathUtils.roundDouble(percentage, 4); double marketPriceAsDouble = marketPrice.getPrice(); - final OfferDirection compareDirection = CurrencyUtil.isCryptoCurrency(currencyCode) ? - OfferDirection.SELL : - OfferDirection.BUY; + final OfferDirection compareDirection = OfferDirection.BUY; double factor = dataModel.getDirection() == compareDirection ? 1 - percentage : 1 + percentage; @@ -614,15 +605,8 @@ public abstract class MutableOfferViewModel ext final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY; - boolean isTraditionalCurrency = CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode()); - - if (isTraditionalCurrency) { - amountDescription = Res.get("createOffer.amountPriceBox.amountDescription", - isBuy ? Res.get("shared.buy") : Res.get("shared.sell")); - } else { - amountDescription = Res.get(isBuy ? "createOffer.amountPriceBox.sell.amountDescriptionCrypto" : - "createOffer.amountPriceBox.buy.amountDescriptionCrypto"); - } + amountDescription = Res.get("createOffer.amountPriceBox.amountDescription", + isBuy ? Res.get("shared.buy") : Res.get("shared.sell")); securityDepositValidator.setPaymentAccount(dataModel.paymentAccount); validateAndSetSecurityDepositToModel(); @@ -1164,29 +1148,14 @@ public abstract class MutableOfferViewModel ext } String getTriggerPriceDescriptionLabel() { - String details; - if (dataModel.isBuyOffer()) { - details = dataModel.isCryptoCurrency() ? - Res.get("account.notifications.marketAlert.message.msg.below") : - Res.get("account.notifications.marketAlert.message.msg.above"); - } else { - details = dataModel.isCryptoCurrency() ? - Res.get("account.notifications.marketAlert.message.msg.above") : - Res.get("account.notifications.marketAlert.message.msg.below"); - } + String details = dataModel.isBuyOffer() ? + Res.get("account.notifications.marketAlert.message.msg.above") : + Res.get("account.notifications.marketAlert.message.msg.below"); return Res.get("createOffer.triggerPrice.label", details); } String getPercentagePriceDescription() { - if (dataModel.isBuyOffer()) { - return dataModel.isCryptoCurrency() ? - Res.get("shared.aboveInPercent") : - Res.get("shared.belowInPercent"); - } else { - return dataModel.isCryptoCurrency() ? - Res.get("shared.belowInPercent") : - Res.get("shared.aboveInPercent"); - } + return dataModel.isBuyOffer() ? Res.get("shared.belowInPercent") : Res.get("shared.aboveInPercent"); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java index dd037593fa..3d26a6ff38 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java @@ -138,7 +138,7 @@ public abstract class OfferView extends ActivatableView { @Override public void onTakeOffer(Offer offer) { - Optional optionalTradeCurrency = CurrencyUtil.getTradeCurrency(offer.getCurrencyCode()); + Optional optionalTradeCurrency = CurrencyUtil.getTradeCurrency(offer.getCounterCurrencyCode()); if (optionalTradeCurrency.isPresent() && canCreateOrTakeOffer(optionalTradeCurrency.get())) { showTakeOffer(offer); } @@ -192,12 +192,10 @@ public abstract class OfferView extends ActivatableView { loadTakeViewClass(viewClass, childViewClass, cryptoOfferBookTab); } else { // add sanity check in case of app restart - if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { - Optional tradeCurrencyOptional = (this.direction == OfferDirection.SELL) ? - CurrencyUtil.getTradeCurrency(preferences.getSellScreenCryptoCurrencyCode()) : - CurrencyUtil.getTradeCurrency(preferences.getBuyScreenCryptoCurrencyCode()); - tradeCurrency = tradeCurrencyOptional.isEmpty() ? OfferViewUtil.getAnyOfMainCryptoCurrencies() : tradeCurrencyOptional.get(); - } + Optional tradeCurrencyOptional = (this.direction == OfferDirection.SELL) ? + CurrencyUtil.getTradeCurrency(preferences.getSellScreenCryptoCurrencyCode()) : + CurrencyUtil.getTradeCurrency(preferences.getBuyScreenCryptoCurrencyCode()); + tradeCurrency = tradeCurrencyOptional.isEmpty() ? OfferViewUtil.getAnyOfMainCryptoCurrencies() : tradeCurrencyOptional.get(); loadCreateViewClass(cryptoOfferBookView, viewClass, childViewClass, cryptoOfferBookTab, (PaymentMethod) data); } tabPane.getSelectionModel().select(cryptoOfferBookTab); @@ -316,7 +314,7 @@ public abstract class OfferView extends ActivatableView { private void showTakeOffer(Offer offer) { this.offer = offer; - Class> offerBookViewClass = getOfferBookViewClassFor(offer.getCurrencyCode()); + Class> offerBookViewClass = getOfferBookViewClassFor(offer.getCounterCurrencyCode()); navigation.navigateTo(MainView.class, this.getClass(), offerBookViewClass, TakeOfferView.class); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java index 64fbfe6798..9f89e69662 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java @@ -100,7 +100,7 @@ public class OfferViewUtil { } public static boolean isShownAsSellOffer(Offer offer) { - return isShownAsSellOffer(offer.getCurrencyCode(), offer.getDirection()); + return isShownAsSellOffer(offer.getCounterCurrencyCode(), offer.getDirection()); } public static boolean isShownAsSellOffer(TradeCurrency tradeCurrency, OfferDirection direction) { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookViewModel.java index e97c08558e..945765bcb9 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookViewModel.java @@ -106,9 +106,9 @@ public class CryptoOfferBookViewModel extends OfferBookViewModel { return offerBookListItem -> { Offer offer = offerBookListItem.getOffer(); boolean directionResult = offer.getDirection() != direction; // offer to buy xmr appears as offer to sell in peer's offer book and vice versa - boolean currencyResult = CurrencyUtil.isCryptoCurrency(offer.getCurrencyCode()) && + boolean currencyResult = CurrencyUtil.isCryptoCurrency(offer.getCounterCurrencyCode()) && (showAllTradeCurrenciesProperty.get() || - offer.getCurrencyCode().equals(selectedTradeCurrency.getCode())); + offer.getCounterCurrencyCode().equals(selectedTradeCurrency.getCode())); boolean paymentMethodResult = showAllPaymentMethods || offer.getPaymentMethod().equals(selectedPaymentMethod); boolean notMyOfferOrShowMyOffersActivated = !isMyOffer(offerBookListItem.getOffer()) || preferences.isShowOwnOffersInOfferBook(); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookViewModel.java index bea41743b6..aef2c57c6f 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookViewModel.java @@ -116,7 +116,7 @@ public class FiatOfferBookViewModel extends OfferBookViewModel { Offer offer = offerBookListItem.getOffer(); boolean directionResult = offer.getDirection() != direction; boolean currencyResult = (showAllTradeCurrenciesProperty.get() && offer.isFiatOffer()) || - offer.getCurrencyCode().equals(selectedTradeCurrency.getCode()); + offer.getCounterCurrencyCode().equals(selectedTradeCurrency.getCode()); boolean paymentMethodResult = showAllPaymentMethods || offer.getPaymentMethod().equals(selectedPaymentMethod); boolean notMyOfferOrShowMyOffersActivated = !isMyOffer(offerBookListItem.getOffer()) || preferences.isShowOwnOffersInOfferBook(); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java index 2e92a9d42d..6f5424a843 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java @@ -234,7 +234,7 @@ public class OfferBook { final String[] ccyCode = new String[1]; final int[] offerCount = new int[1]; offerBookListItems.forEach(o -> { - ccyCode[0] = o.getOffer().getCurrencyCode(); + ccyCode[0] = o.getOffer().getCounterCurrencyCode(); if (o.getOffer().getDirection() == BUY) { offerCount[0] = buyOfferCountMap.getOrDefault(ccyCode[0], 0) + 1; buyOfferCountMap.put(ccyCode[0], offerCount[0]); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java index e340f9676c..353d4e87d4 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java @@ -67,9 +67,9 @@ public class OfferBookListItem { public WitnessAgeData getWitnessAgeData(AccountAgeWitnessService accountAgeWitnessService, SignedWitnessService signedWitnessService) { if (witnessAgeData == null) { - if (CurrencyUtil.isCryptoCurrency(offer.getCurrencyCode())) { + if (CurrencyUtil.isCryptoCurrency(offer.getCounterCurrencyCode())) { witnessAgeData = new WitnessAgeData(WitnessAgeData.TYPE_CRYPTOS); - } else if (PaymentMethod.hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode())) { + } else if (PaymentMethod.hasChargebackRisk(offer.getPaymentMethod(), offer.getCounterCurrencyCode())) { // Fiat and signed witness required Optional optionalWitness = accountAgeWitnessService.findWitness(offer); AccountAgeWitnessService.SignState signState = optionalWitness diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java index 2129f3c6dc..b2ce32149b 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java @@ -263,7 +263,7 @@ abstract public class OfferBookView CurrencyUtil.getCurrencyPair(o.getOffer().getCurrencyCode()), + o -> CurrencyUtil.getCurrencyPair(o.getOffer().getCounterCurrencyCode()), Comparator.nullsFirst(Comparator.naturalOrder()) )); @@ -677,7 +677,7 @@ abstract public class OfferBookView account = model.getMostMaturePaymentAccountForOffer(offer); if (account.isPresent()) { long tradeLimit = model.accountAgeWitnessService.getMyTradeLimit(account.get(), - offer.getCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()); + offer.getCounterCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()); new Popup() .warning(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.buyer", HavenoUtils.formatXmr(tradeLimit, true), @@ -824,7 +824,7 @@ abstract public class OfferBookView { offerDetailsWindow.show(offer); }); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java index 85ecb1e781..94982f7490 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -448,7 +448,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { Volume offerVolume = offer.getVolume(); Volume minOfferVolume = offer.getMinVolume(); if (offerVolume != null && minOfferVolume != null) { - String postFix = appendCurrencyCode ? " " + offer.getCurrencyCode() : ""; + String postFix = appendCurrencyCode ? " " + offer.getCounterCurrencyCode() : ""; decimalAligned = decimalAligned && !showAllTradeCurrenciesProperty.get(); return VolumeUtil.formatVolume(offer, decimalAligned, maxPlacesForVolume.get()) + postFix; } else { @@ -457,7 +457,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { } int getNumberOfDecimalsForVolume(OfferBookListItem item) { - return CurrencyUtil.isVolumeRoundedToNearestUnit(item.getOffer().getCurrencyCode()) ? GUIUtil.NUM_DECIMALS_UNIT : GUIUtil.NUM_DECIMALS_PRECISE; + return CurrencyUtil.isVolumeRoundedToNearestUnit(item.getOffer().getCounterCurrencyCode()) ? GUIUtil.NUM_DECIMALS_UNIT : GUIUtil.NUM_DECIMALS_PRECISE; } String getPaymentMethod(OfferBookListItem item) { @@ -484,14 +484,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { if (item != null) { Offer offer = item.getOffer(); result = Res.getWithCol("shared.paymentMethod") + " " + Res.get(offer.getPaymentMethod().getId()); - result += "\n" + Res.getWithCol("shared.currency") + " " + CurrencyUtil.getNameAndCode(offer.getCurrencyCode()); - - if (offer.isXmr()) { - String isAutoConf = offer.isXmrAutoConf() ? - Res.get("shared.yes") : - Res.get("shared.no"); - result += "\n" + Res.getWithCol("offerbook.xmrAutoConf") + " " + isAutoConf; - } + result += "\n" + Res.getWithCol("shared.currency") + " " + CurrencyUtil.getNameAndCode(offer.getCounterCurrencyCode()); String countryCode = offer.getCountryCode(); if (isF2F(offer)) { @@ -538,7 +531,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { } String getDirectionLabelTooltip(Offer offer) { - return getDirectionWithCodeDetailed(offer.getMirroredDirection(), offer.getCurrencyCode()); + return getDirectionWithCodeDetailed(offer.getMirroredDirection(), offer.getCounterCurrencyCode()); } Optional getMostMaturePaymentAccountForOffer(Offer offer) { @@ -623,9 +616,9 @@ abstract class OfferBookViewModel extends ActivatableViewModel { // filter currencies nextPredicate = nextPredicate.or(offerBookListItem -> { - return offerBookListItem.getOffer().getCurrencyCode().toLowerCase().contains(filterText.toLowerCase()) || + return offerBookListItem.getOffer().getCounterCurrencyCode().toLowerCase().contains(filterText.toLowerCase()) || offerBookListItem.getOffer().getBaseCurrencyCode().toLowerCase().contains(filterText.toLowerCase()) || - CurrencyUtil.getNameAndCode(offerBookListItem.getOffer().getCurrencyCode()).toLowerCase().contains(filterText.toLowerCase()) || + CurrencyUtil.getNameAndCode(offerBookListItem.getOffer().getCounterCurrencyCode()).toLowerCase().contains(filterText.toLowerCase()) || CurrencyUtil.getNameAndCode(offerBookListItem.getOffer().getBaseCurrencyCode()).toLowerCase().contains(filterText.toLowerCase()); }); @@ -691,10 +684,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { } private static String getDirectionWithCodeDetailed(OfferDirection direction, String currencyCode) { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) - return (direction == OfferDirection.BUY) ? Res.get("shared.buyingXMRWith", currencyCode) : Res.get("shared.sellingXMRFor", currencyCode); - else - return (direction == OfferDirection.SELL) ? Res.get("shared.buyingCurrency", currencyCode) : Res.get("shared.sellingCurrency", currencyCode); + return (direction == OfferDirection.BUY) ? Res.get("shared.buyingXMRWith", currencyCode) : Res.get("shared.sellingXMRFor", currencyCode); } public String formatDepositString(BigInteger deposit, long amount) { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java index 012af7a822..0d9042e4e5 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java @@ -112,8 +112,8 @@ public class OtherOfferBookViewModel extends OfferBookViewModel { return offerBookListItem -> { Offer offer = offerBookListItem.getOffer(); boolean directionResult = offer.getDirection() != direction; - boolean currencyResult = CurrencyUtil.isTraditionalCurrency(offer.getCurrencyCode()) && !CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) && - (showAllTradeCurrenciesProperty.get() || offer.getCurrencyCode().equals(selectedTradeCurrency.getCode())); + boolean currencyResult = CurrencyUtil.isTraditionalCurrency(offer.getCounterCurrencyCode()) && !CurrencyUtil.isFiatCurrency(offer.getCounterCurrencyCode()) && + (showAllTradeCurrenciesProperty.get() || offer.getCounterCurrencyCode().equals(selectedTradeCurrency.getCode())); boolean paymentMethodResult = showAllPaymentMethods || offer.getPaymentMethod().equals(selectedPaymentMethod); boolean notMyOfferOrShowMyOffersActivated = !isMyOffer(offerBookListItem.getOffer()) || preferences.isShowOwnOffersInOfferBook(); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java index e8da31e3bf..bd3beef971 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -146,7 +146,7 @@ class TakeOfferDataModel extends OfferDataModel { // feeFromFundingTxProperty.set(FeePolicy.getMinRequiredFeeForFundingTx()); if (isTabSelected) - priceFeedService.setCurrencyCode(offer.getCurrencyCode()); + priceFeedService.setCurrencyCode(offer.getCounterCurrencyCode()); if (canTakeOffer()) { tradeManager.checkOfferAvailability(offer, @@ -204,7 +204,7 @@ class TakeOfferDataModel extends OfferDataModel { offer.resetState(); - priceFeedService.setCurrencyCode(offer.getCurrencyCode()); + priceFeedService.setCurrencyCode(offer.getCounterCurrencyCode()); } // We don't want that the fee gets updated anymore after we show the funding screen. @@ -215,7 +215,7 @@ class TakeOfferDataModel extends OfferDataModel { void onTabSelected(boolean isSelected) { this.isTabSelected = isSelected; if (isTabSelected) - priceFeedService.setCurrencyCode(offer.getCurrencyCode()); + priceFeedService.setCurrencyCode(offer.getCounterCurrencyCode()); } public void onClose(boolean removeOffer) { @@ -259,7 +259,7 @@ class TakeOfferDataModel extends OfferDataModel { fundsNeededForTrade = fundsNeededForTrade.add(amount.get()); String errorMsg = null; - if (filterManager.isCurrencyBanned(offer.getCurrencyCode())) { + if (filterManager.isCurrencyBanned(offer.getCounterCurrencyCode())) { errorMsg = Res.get("offerbook.warning.currencyBanned"); } else if (filterManager.isPaymentMethodBanned(offer.getPaymentMethod())) { errorMsg = Res.get("offerbook.warning.paymentMethodBanned"); @@ -501,11 +501,11 @@ class TakeOfferDataModel extends OfferDataModel { } public String getCurrencyCode() { - return offer.getCurrencyCode(); + return offer.getCounterCurrencyCode(); } public String getCurrencyNameAndCode() { - return CurrencyUtil.getNameByCode(offer.getCurrencyCode()); + return CurrencyUtil.getNameByCode(offer.getCounterCurrencyCode()); } @NotNull diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java index bf929d6f3b..bb807b8a9b 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java @@ -1266,12 +1266,6 @@ public class TakeOfferView extends ActivatableViewAndModel im addBindings(); addListeners(); - String buyVolumeDescriptionKey = offer.isTraditionalOffer() ? "createOffer.amountPriceBox.buy.volumeDescription" : - "createOffer.amountPriceBox.buy.volumeDescriptionCrypto"; - String sellVolumeDescriptionKey = offer.isTraditionalOffer() ? "createOffer.amountPriceBox.sell.volumeDescription" : - "createOffer.amountPriceBox.sell.volumeDescriptionCrypto"; + String buyVolumeDescriptionKey = "createOffer.amountPriceBox.buy.volumeDescription"; + String sellVolumeDescriptionKey = "createOffer.amountPriceBox.sell.volumeDescription"; if (dataModel.getDirection() == OfferDirection.SELL) { volumeDescriptionLabel.set(Res.get(buyVolumeDescriptionKey, dataModel.getCurrencyCode())); @@ -695,7 +693,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel im public boolean isSellingToAnUnsignedAccount(Offer offer) { if (offer.getDirection() == OfferDirection.BUY && - PaymentMethod.hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode())) { + PaymentMethod.hasChargebackRisk(offer.getPaymentMethod(), offer.getCounterCurrencyCode())) { // considered risky when either UNSIGNED, PEER_INITIAL, or BANNED (see #5343) return accountAgeWitnessService.getSignState(offer) == AccountAgeWitnessService.SignState.UNSIGNED || accountAgeWitnessService.getSignState(offer) == AccountAgeWitnessService.SignState.PEER_INITIAL || @@ -792,14 +790,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel im } String getPercentagePriceDescription() { - if (dataModel.isBuyOffer()) { - return dataModel.isCryptoCurrency() ? - Res.get("shared.aboveInPercent") : - Res.get("shared.belowInPercent"); - } else { - return dataModel.isCryptoCurrency() ? - Res.get("shared.belowInPercent") : - Res.get("shared.aboveInPercent"); - } + return dataModel.isBuyOffer() ? Res.get("shared.belowInPercent") : Res.get("shared.aboveInPercent"); } } diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java index 7f72fb2e10..4bc6add0b0 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java @@ -141,7 +141,7 @@ public class ContractWindow extends Overlay { addSeparator(gridPane, ++rowIndex); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("contractWindow.dates"), DisplayUtils.formatDateTime(offer.getDate()) + " / " + DisplayUtils.formatDateTime(dispute.getTradeDate())); - String currencyCode = offer.getCurrencyCode(); + String currencyCode = offer.getCounterCurrencyCode(); addSeparator(gridPane, ++rowIndex); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.offerType"), DisplayUtils.getDirectionBothSides(offer.getDirection(), offer.isPrivateOffer())); diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java index c414df2222..c1dba2b71c 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java @@ -202,17 +202,12 @@ public class OfferDetailsWindow extends Overlay { if (isF2F) rows++; - boolean showXmrAutoConf = offer.isXmr() && offer.getDirection() == OfferDirection.SELL; - if (showXmrAutoConf) { - rows++; - } - addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.Offer")); String counterCurrencyDirectionInfo = ""; String xmrDirectionInfo = ""; OfferDirection direction = offer.getDirection(); - String currencyCode = offer.getCurrencyCode(); + String currencyCode = offer.getCounterCurrencyCode(); String offerTypeLabel = Res.get("shared.offerType"); String toReceive = " " + Res.get("shared.toReceive"); String toSpend = " " + Res.get("shared.toSpend"); @@ -291,14 +286,6 @@ public class OfferDetailsWindow extends Overlay { addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.paymentMethod"), method); } - if (showXmrAutoConf) { - addSeparator(gridPane, ++rowIndex); - String isAutoConf = offer.isXmrAutoConf() ? - Res.get("shared.yes") : - Res.get("shared.no"); - addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerbook.xmrAutoConf"), isAutoConf); - } - if (showAcceptedBanks) { if (paymentMethod.equals(PaymentMethod.SAME_BANK)) { addSeparator(gridPane, ++rowIndex); @@ -474,11 +461,11 @@ public class OfferDetailsWindow extends Overlay { boolean isBuyOffer = offer.isBuyOffer(); boolean isBuyerRole = isPlaceOffer == isBuyOffer; String placeOfferButtonText = isBuyerRole ? - Res.get("offerDetailsWindow.confirm.maker", Res.get("shared.buy")) : - Res.get("offerDetailsWindow.confirm.maker", Res.get("shared.sell")); + Res.get("offerDetailsWindow.confirm.maker.buy", offer.getCounterCurrencyCode()) : + Res.get("offerDetailsWindow.confirm.maker.sell", offer.getCounterCurrencyCode()); String takeOfferButtonText = isBuyerRole ? - Res.get("offerDetailsWindow.confirm.taker", Res.get("shared.buy")) : - Res.get("offerDetailsWindow.confirm.taker", Res.get("shared.sell")); + Res.get("offerDetailsWindow.confirm.taker.buy", offer.getCounterCurrencyCode()) : + Res.get("offerDetailsWindow.confirm.taker.sell", offer.getCounterCurrencyCode()); Tuple4 placeOfferTuple = addButtonBusyAnimationLabelAfterGroup(gridPane, ++rowIndex, 1, diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java index 451b440ab9..437dc8eaf9 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java @@ -144,12 +144,12 @@ public class TradeDetailsWindow extends Overlay { String offerType = Res.get("shared.offerType"); if (tradeManager.isBuyer(offer)) { addConfirmationLabelTextField(gridPane, rowIndex, offerType, - DisplayUtils.getDirectionForBuyer(myOffer, offer.getCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE); + DisplayUtils.getDirectionForBuyer(myOffer, offer.getCounterCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE); counterCurrencyDirectionInfo = toSpend; xmrDirectionInfo = toReceive; } else { addConfirmationLabelTextField(gridPane, rowIndex, offerType, - DisplayUtils.getDirectionForSeller(myOffer, offer.getCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE); + DisplayUtils.getDirectionForSeller(myOffer, offer.getCounterCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE); counterCurrencyDirectionInfo = toReceive; xmrDirectionInfo = toSpend; } @@ -159,7 +159,7 @@ public class TradeDetailsWindow extends Overlay { HavenoUtils.formatXmr(trade.getAmount(), true)); addSeparator(gridPane, ++rowIndex); addConfirmationLabelTextField(gridPane, ++rowIndex, - VolumeUtil.formatVolumeLabel(offer.getCurrencyCode()) + counterCurrencyDirectionInfo, + VolumeUtil.formatVolumeLabel(offer.getCounterCurrencyCode()) + counterCurrencyDirectionInfo, VolumeUtil.formatVolumeWithCode(trade.getVolume())); addSeparator(gridPane, ++rowIndex); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradePrice"), diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferDataModel.java index 24d792005c..f1c53bcab1 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferDataModel.java @@ -108,12 +108,12 @@ class CloneOfferDataModel extends MutableOfferDataModel { Offer offer = openOffer.getOffer(); direction = offer.getDirection(); - CurrencyUtil.getTradeCurrency(offer.getCurrencyCode()) + CurrencyUtil.getTradeCurrency(offer.getCounterCurrencyCode()) .ifPresent(c -> this.tradeCurrency = c); - tradeCurrencyCode.set(offer.getCurrencyCode()); + tradeCurrencyCode.set(offer.getCounterCurrencyCode()); PaymentAccount tmpPaymentAccount = user.getPaymentAccount(openOffer.getOffer().getMakerPaymentAccountId()); - Optional optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode()); + Optional optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode()); if (optionalTradeCurrency.isPresent() && tmpPaymentAccount != null) { TradeCurrency selectedTradeCurrency = optionalTradeCurrency.get(); this.paymentAccount = PaymentAccount.fromProto(tmpPaymentAccount.toProtoMessage(), corePersistenceProtoResolver); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferView.java index e48bdf80a7..160182e608 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/cloneoffer/CloneOfferView.java @@ -144,7 +144,7 @@ public class CloneOfferView extends MutableOfferView { model.applyOpenOffer(openOffer); initWithData(openOffer.getOffer().getDirection(), - CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode()).get(), + CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode()).get(), false, null); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java index 7b6ca92a19..9185068d4e 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java @@ -104,7 +104,7 @@ public class ClosedTradesListItem implements FilterableListItem { OfferDirection direction = closedTradableManager.wasMyOffer(offer) || tradable instanceof ArbitratorTrade ? offer.getDirection() : offer.getMirroredDirection(); - String currencyCode = tradable.getOffer().getCurrencyCode(); + String currencyCode = tradable.getOffer().getCounterCurrencyCode(); return DisplayUtils.getDirectionWithCode(direction, currencyCode, offer.isPrivateOffer()); } @@ -117,7 +117,7 @@ public class ClosedTradesListItem implements FilterableListItem { } public String getMarketLabel() { - return CurrencyUtil.getCurrencyPair(tradable.getOffer().getCurrencyCode()); + return CurrencyUtil.getCurrencyPair(tradable.getOffer().getCounterCurrencyCode()); } public String getState() { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java index 530cad9c86..1795637ee9 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java @@ -108,13 +108,13 @@ class EditOfferDataModel extends MutableOfferDataModel { Offer offer = openOffer.getOffer(); direction = offer.getDirection(); - CurrencyUtil.getTradeCurrency(offer.getCurrencyCode()) + CurrencyUtil.getTradeCurrency(offer.getCounterCurrencyCode()) .ifPresent(c -> this.tradeCurrency = c); - tradeCurrencyCode.set(offer.getCurrencyCode()); + tradeCurrencyCode.set(offer.getCounterCurrencyCode()); this.initialState = openOffer.getState(); PaymentAccount tmpPaymentAccount = user.getPaymentAccount(openOffer.getOffer().getMakerPaymentAccountId()); - Optional optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode()); + Optional optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode()); if (optionalTradeCurrency.isPresent() && tmpPaymentAccount != null) { TradeCurrency selectedTradeCurrency = optionalTradeCurrency.get(); this.paymentAccount = PaymentAccount.fromProto(tmpPaymentAccount.toProtoMessage(), corePersistenceProtoResolver); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java index 8b1d9775e6..070aac8d01 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java @@ -141,7 +141,7 @@ public class EditOfferView extends MutableOfferView { model.applyOpenOffer(openOffer); initWithData(openOffer.getOffer().getDirection(), - CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode()).get(), + CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode()).get(), false, null); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java index b6dd35d3a5..caf5fcd848 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java @@ -68,14 +68,14 @@ class FailedTradesViewModel extends ActivatableWithDataModel } String getVolume(OpenOfferListItem item) { - return (item != null) ? VolumeUtil.formatVolume(item.getOffer(), false, 0) + " " + item.getOffer().getCurrencyCode() : ""; + return (item != null) ? VolumeUtil.formatVolume(item.getOffer(), false, 0) + " " + item.getOffer().getCounterCurrencyCode() : ""; } String getDirectionLabel(OpenOfferListItem item) { if ((item == null)) return ""; - return DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getOffer()), item.getOffer().getCurrencyCode(), item.getOffer().isPrivateOffer()); + return DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getOffer()), item.getOffer().getCounterCurrencyCode(), item.getOffer().isPrivateOffer()); } String getMarketLabel(OpenOfferListItem item) { if ((item == null)) return ""; - return CurrencyUtil.getCurrencyPair(item.getOffer().getCurrencyCode()); + return CurrencyUtil.getCurrencyPair(item.getOffer().getCounterCurrencyCode()); } String getPaymentMethod(OpenOfferListItem item) { @@ -168,7 +168,7 @@ class OpenOffersViewModel extends ActivatableWithDataModel if (!offer.isUseMarketBasedPrice() || triggerPrice <= 0) { return Res.get("shared.na"); } else { - return PriceUtil.formatMarketPrice(triggerPrice, offer.getCurrencyCode()); + return PriceUtil.formatMarketPrice(triggerPrice, offer.getCounterCurrencyCode()); } } } diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java index 3b9a399e82..47d1c155b9 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java @@ -63,7 +63,7 @@ public class PendingTradesListItem implements FilterableListItem { } public String getMarketDescription() { - return getCurrencyPair(trade.getOffer().getCurrencyCode()); + return getCurrencyPair(trade.getOffer().getCounterCurrencyCode()); } @Override diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java index b7ac1b1886..779d86ea12 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java @@ -743,7 +743,7 @@ public abstract class TradeStepView extends AnchorPane { } protected String getCurrencyCode(Trade trade) { - return checkNotNull(trade.getOffer()).getCurrencyCode(); + return checkNotNull(trade.getOffer()).getCounterCurrencyCode(); } protected boolean isXmrTrade() { diff --git a/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java b/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java index 8c725188c1..d49f302b30 100644 --- a/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java +++ b/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java @@ -3,7 +3,6 @@ package haveno.desktop.util; import haveno.common.crypto.PubKeyRing; import haveno.core.account.witness.AccountAgeWitness; import haveno.core.account.witness.AccountAgeWitnessService; -import haveno.core.locale.CurrencyUtil; import haveno.core.locale.GlobalSettings; import haveno.core.locale.Res; import haveno.core.monetary.Price; @@ -118,10 +117,7 @@ public class DisplayUtils { /////////////////////////////////////////////////////////////////////////////////////////// public static String getDirectionWithCode(OfferDirection direction, String currencyCode, boolean isPrivate) { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) - return (direction == OfferDirection.BUY) ? Res.get("shared.buyCurrency" + (isPrivate ? LOCKED : ""), Res.getBaseCurrencyCode()) : Res.get("shared.sellCurrency" + (isPrivate ? LOCKED : ""), Res.getBaseCurrencyCode()); - else - return (direction == OfferDirection.SELL) ? Res.get("shared.buyCurrency" + (isPrivate ? LOCKED : ""), currencyCode) : Res.get("shared.sellCurrency" + (isPrivate ? LOCKED : ""), currencyCode); + return (direction == OfferDirection.BUY) ? Res.get("shared.buyCurrency" + (isPrivate ? LOCKED : ""), Res.getBaseCurrencyCode()) : Res.get("shared.sellCurrency" + (isPrivate ? LOCKED : ""), Res.getBaseCurrencyCode()); } public static String getDirectionBothSides(OfferDirection direction, boolean isPrivate) { @@ -132,56 +128,31 @@ public class DisplayUtils { } public static String getDirectionForBuyer(boolean isMyOffer, String currencyCode) { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - String code = Res.getBaseCurrencyCode(); - return isMyOffer ? - Res.get("formatter.youAreAsMaker", Res.get("shared.buyer"), code, Res.get("shared.seller"), code) : - Res.get("formatter.youAreAsTaker", Res.get("shared.buyer"), code, Res.get("shared.seller"), code); - } else { - return isMyOffer ? - Res.get("formatter.youAreAsMaker", Res.get("shared.seller"), currencyCode, Res.get("shared.buyer"), currencyCode) : - Res.get("formatter.youAreAsTaker", Res.get("shared.seller"), currencyCode, Res.get("shared.buyer"), currencyCode); - } + String code = Res.getBaseCurrencyCode(); + return isMyOffer ? + Res.get("formatter.youAreAsMaker", Res.get("shared.buyer"), code, Res.get("shared.seller"), code) : + Res.get("formatter.youAreAsTaker", Res.get("shared.buyer"), code, Res.get("shared.seller"), code); } public static String getDirectionForSeller(boolean isMyOffer, String currencyCode) { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - String code = Res.getBaseCurrencyCode(); - return isMyOffer ? - Res.get("formatter.youAreAsMaker", Res.get("shared.seller"), code, Res.get("shared.buyer"), code) : - Res.get("formatter.youAreAsTaker", Res.get("shared.seller"), code, Res.get("shared.buyer"), code); - } else { - return isMyOffer ? - Res.get("formatter.youAreAsMaker", Res.get("shared.buyer"), currencyCode, Res.get("shared.seller"), currencyCode) : - Res.get("formatter.youAreAsTaker", Res.get("shared.buyer"), currencyCode, Res.get("shared.seller"), currencyCode); - } + String code = Res.getBaseCurrencyCode(); + return isMyOffer ? + Res.get("formatter.youAreAsMaker", Res.get("shared.seller"), code, Res.get("shared.buyer"), code) : + Res.get("formatter.youAreAsTaker", Res.get("shared.seller"), code, Res.get("shared.buyer"), code); } public static String getDirectionForTakeOffer(OfferDirection direction, String currencyCode) { String baseCurrencyCode = Res.getBaseCurrencyCode(); - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - return direction == OfferDirection.BUY ? - Res.get("formatter.youAre", Res.get("shared.selling"), baseCurrencyCode, Res.get("shared.buying"), currencyCode) : - Res.get("formatter.youAre", Res.get("shared.buying"), baseCurrencyCode, Res.get("shared.selling"), currencyCode); - } else { - - return direction == OfferDirection.SELL ? - Res.get("formatter.youAre", Res.get("shared.selling"), currencyCode, Res.get("shared.buying"), baseCurrencyCode) : - Res.get("formatter.youAre", Res.get("shared.buying"), currencyCode, Res.get("shared.selling"), baseCurrencyCode); - } + return direction == OfferDirection.BUY ? + Res.get("formatter.youAre", Res.get("shared.selling"), baseCurrencyCode, Res.get("shared.buying"), currencyCode) : + Res.get("formatter.youAre", Res.get("shared.buying"), baseCurrencyCode, Res.get("shared.selling"), currencyCode); } public static String getOfferDirectionForCreateOffer(OfferDirection direction, String currencyCode, boolean isPrivate) { String baseCurrencyCode = Res.getBaseCurrencyCode(); - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - return direction == OfferDirection.BUY ? - Res.get("formatter.youAreCreatingAnOffer.traditional" + (isPrivate ? LOCKED : ""), Res.get("shared.buy"), baseCurrencyCode) : - Res.get("formatter.youAreCreatingAnOffer.traditional" + (isPrivate ? LOCKED : ""), Res.get("shared.sell"), baseCurrencyCode); - } else { - return direction == OfferDirection.SELL ? - Res.get("formatter.youAreCreatingAnOffer.crypto" + (isPrivate ? LOCKED : ""), Res.get("shared.buy"), currencyCode, Res.get("shared.selling"), baseCurrencyCode) : - Res.get("formatter.youAreCreatingAnOffer.crypto" + (isPrivate ? LOCKED : ""), Res.get("shared.sell"), currencyCode, Res.get("shared.buying"), baseCurrencyCode); - } + return direction == OfferDirection.BUY ? + Res.get("formatter.youAreCreatingAnOffer.traditional" + (isPrivate ? LOCKED : ""), Res.get("shared.buy"), baseCurrencyCode) : + Res.get("formatter.youAreCreatingAnOffer.traditional" + (isPrivate ? LOCKED : ""), Res.get("shared.sell"), baseCurrencyCode); } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java b/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java index 19756fc523..cf871529dc 100644 --- a/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java @@ -217,7 +217,7 @@ public class CreateOfferViewModelTest { model.amount.set("0.01"); model.onFocusOutPriceAsPercentageTextField(true, false); //leave focus without changing assertEquals("0.00", model.marketPriceMargin.get()); - assertEquals("0.00000078", model.volume.get()); + assertEquals("126.84045000", model.volume.get()); assertEquals("12684.04500000", model.price.get()); } }