mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-08-06 21:54:19 -04:00
remove inverted crypto prices; always use price per XMR (base/quote) (#1821)
This commit is contained in:
parent
51d40d73a7
commit
a4d744aa53
89 changed files with 588 additions and 728 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ public class CoreOffersService {
|
|||
List<OpenOffer> 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<Transaction> 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<OpenOffer> openOfferPriceComparator(String direction, boolean isTraditional) {
|
||||
private Comparator<OpenOffer> 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) {
|
||||
|
|
|
@ -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<MarketPriceInfo> 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<Offer> 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<Offer> 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<Double,Double> sellTM = new LinkedHashMap<Double,Double>();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<Price> 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);
|
||||
|
|
|
@ -57,7 +57,7 @@ public class TradeInfo implements Payload {
|
|||
|
||||
private static final Function<Trade, String> 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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -136,7 +136,7 @@ public class Price extends MonetaryWrapper implements Comparable<Price> {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,84 +15,84 @@
|
|||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<String> acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount);
|
||||
String bankId = PaymentAccountUtil.getBankId(paymentAccount);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -271,7 +271,7 @@ public class OfferBookService {
|
|||
|
||||
public List<Offer> 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<OfferForJson> 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(),
|
||||
|
|
|
@ -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={}, ",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<? extends OpenOffer> 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<? extends OpenOffer> openOffers) {
|
||||
openOffers.forEach(openOffer -> {
|
||||
String currencyCode = openOffer.getOffer().getCurrencyCode();
|
||||
String currencyCode = openOffer.getOffer().getCounterCurrencyCode();
|
||||
if (openOffersByCurrency.containsKey(currencyCode)) {
|
||||
Set<OpenOffer> set = openOffersByCurrency.get(currencyCode);
|
||||
set.remove(openOffer);
|
||||
|
|
|
@ -100,7 +100,7 @@ public class ValidateOffer extends Task<PlaceOfferModel> {
|
|||
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<PlaceOfferModel> {
|
|||
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");
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 +
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<TradeStatistics3> tradeStats) {
|
||||
private void removeDuplicateStats(Set<TradeStatistics3> tradeStats) {
|
||||
removeEarlyDuplicateStats(tradeStats);
|
||||
removeEarlyDuplicateStatsFuzzy(tradeStats);
|
||||
}
|
||||
|
||||
private void removeEarlyDuplicateStats(Set<TradeStatistics3> tradeStats) {
|
||||
|
||||
// collect trades before September 30, 2024
|
||||
Set<TradeStatistics3> 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<TradeStatistics3> duplicates = new HashSet<>();
|
||||
Set<TradeStatistics3> 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<TradeStatistics3> 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<TradeStatistics3> tradeStats) {
|
||||
|
||||
// collect trades before August 7, 2024
|
||||
Set<TradeStatistics3> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,15 +66,15 @@ public class AveragePriceUtil {
|
|||
private static List<TradeStatistics3> removeOutliers(List<TradeStatistics3> list, double percentToTrim) {
|
||||
List<Double> yValues = list.stream()
|
||||
.filter(TradeStatistics3::isValid)
|
||||
.map(e -> (double) e.getPrice())
|
||||
.map(e -> (double) e.getNormalizedPrice())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Tuple2<Double, Double> 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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=オファーパスフレーズ
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=Пароль предложения
|
||||
|
|
|
@ -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=รหัสผ่านสำหรับข้อเสนอ
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=提供密码
|
||||
|
|
|
@ -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=提供密碼
|
||||
|
|
|
@ -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."
|
||||
);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ public class MarketView extends ActivatableView<TabPane, Void> {
|
|||
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")
|
||||
|
|
|
@ -236,19 +236,19 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
}
|
||||
});
|
||||
|
||||
String viewBaseCurrencyCode = model.isCrypto() ? code : Res.getBaseCurrencyCode();
|
||||
String viewPriceCurrencyCode = model.isCrypto() ? Res.getBaseCurrencyCode() : code;
|
||||
String viewBaseCurrencyCode = Res.getBaseCurrencyCode();
|
||||
String viewPriceCurrencyCode = code;
|
||||
|
||||
sellHeaderLabel.setText(Res.get("market.offerBook.sellOffersHeaderLabel", viewBaseCurrencyCode));
|
||||
sellButton.updateText(Res.get("shared.sellCurrency", viewBaseCurrencyCode));
|
||||
sellButton.setGraphic(GUIUtil.getCurrencyIconWithBorder(viewBaseCurrencyCode));
|
||||
sellButton.setOnAction(e -> 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<VBox, OfferBookC
|
|||
private synchronized void updateChartData() {
|
||||
|
||||
// update volume headers
|
||||
Volume volumeSell = model.getTotalVolume(model.isCrypto() ? OfferDirection.BUY : OfferDirection.SELL);
|
||||
Volume volumeBuy = model.getTotalVolume(model.isCrypto() ? OfferDirection.SELL : OfferDirection.BUY);
|
||||
Volume volumeSell = model.getTotalVolume(OfferDirection.SELL);
|
||||
Volume volumeBuy = model.getTotalVolume(OfferDirection.BUY);
|
||||
String formattedVolumeSell = volumeSell == null ? null : VolumeUtil.formatVolume(volumeSell);
|
||||
String formattedVolumeBuy = volumeBuy == null ? null : VolumeUtil.formatVolume(volumeBuy);
|
||||
if (model.getSellData().isEmpty()) formattedVolumeSell = "0.0";
|
||||
|
@ -368,8 +368,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
volumeBuyColumnLabel.set(Res.get("offerbook.volumeTotal", model.getCurrencyCode(), formattedVolumeBuy == null ? "" : "(" + formattedVolumeBuy + ")"));
|
||||
|
||||
// update amount headers
|
||||
amountSellColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(model.isCrypto() ? OfferDirection.BUY : OfferDirection.SELL)));
|
||||
amountBuyColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(model.isCrypto() ? OfferDirection.SELL : OfferDirection.BUY)));
|
||||
amountSellColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(OfferDirection.SELL)));
|
||||
amountBuyColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(OfferDirection.BUY)));
|
||||
|
||||
seriesSell.getData().clear();
|
||||
seriesBuy.getData().clear();
|
||||
|
|
|
@ -130,7 +130,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
|
|||
list.addAll(c.getAddedSubList());
|
||||
if (list.stream()
|
||||
.map(OfferBookListItem::getOffer)
|
||||
.anyMatch(e -> 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<TradeCurrency> tradeCurrencyList = offerBookListItems.stream()
|
||||
.map(e -> {
|
||||
String currencyCode = e.getOffer().getCurrencyCode();
|
||||
String currencyCode = e.getOffer().getCounterCurrencyCode();
|
||||
Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(currencyCode);
|
||||
return tradeCurrencyOptional.orElse(null);
|
||||
})
|
||||
|
@ -221,7 +221,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
|
|||
synchronized (offerBookListItems) {
|
||||
List<Offer> 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<Volume> 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<Offer> 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<Offer> 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<Offer> 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<Offer> 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());
|
||||
|
|
|
@ -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<Offer> offers = offersByCurrencyMap.get(key);
|
||||
boolean iTraditionalCurrency = (offers.size() > 0 && offers.get(0).getPaymentMethod().isTraditional());
|
||||
|
||||
List<Offer> uniqueOffers = offers.stream().filter(distinctByKey(Offer::getId)).collect(Collectors.toList());
|
||||
|
||||
List<Offer> 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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(() -> {
|
||||
|
|
|
@ -321,20 +321,12 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> 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<M extends MutableOfferViewModel<?>> 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) -> {
|
||||
|
|
|
@ -261,15 +261,11 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> 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<M extends MutableOfferDataModel> 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<M extends MutableOfferDataModel> 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<M extends MutableOfferDataModel> 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<M extends MutableOfferDataModel> 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<M extends MutableOfferDataModel> 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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
|||
|
||||
@Override
|
||||
public void onTakeOffer(Offer offer) {
|
||||
Optional<TradeCurrency> optionalTradeCurrency = CurrencyUtil.getTradeCurrency(offer.getCurrencyCode());
|
||||
Optional<TradeCurrency> optionalTradeCurrency = CurrencyUtil.getTradeCurrency(offer.getCounterCurrencyCode());
|
||||
if (optionalTradeCurrency.isPresent() && canCreateOrTakeOffer(optionalTradeCurrency.get())) {
|
||||
showTakeOffer(offer);
|
||||
}
|
||||
|
@ -192,12 +192,10 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
|||
loadTakeViewClass(viewClass, childViewClass, cryptoOfferBookTab);
|
||||
} else {
|
||||
// add sanity check in case of app restart
|
||||
if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) {
|
||||
Optional<TradeCurrency> tradeCurrencyOptional = (this.direction == OfferDirection.SELL) ?
|
||||
CurrencyUtil.getTradeCurrency(preferences.getSellScreenCryptoCurrencyCode()) :
|
||||
CurrencyUtil.getTradeCurrency(preferences.getBuyScreenCryptoCurrencyCode());
|
||||
tradeCurrency = tradeCurrencyOptional.isEmpty() ? OfferViewUtil.getAnyOfMainCryptoCurrencies() : tradeCurrencyOptional.get();
|
||||
}
|
||||
Optional<TradeCurrency> 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<TabPane, Void> {
|
|||
private void showTakeOffer(Offer offer) {
|
||||
this.offer = offer;
|
||||
|
||||
Class<? extends OfferBookView<?, ?>> offerBookViewClass = getOfferBookViewClassFor(offer.getCurrencyCode());
|
||||
Class<? extends OfferBookView<?, ?>> offerBookViewClass = getOfferBookViewClassFor(offer.getCounterCurrencyCode());
|
||||
navigation.navigateTo(MainView.class, this.getClass(), offerBookViewClass, TakeOfferView.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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<AccountAgeWitness> optionalWitness = accountAgeWitnessService.findWitness(offer);
|
||||
AccountAgeWitnessService.SignState signState = optionalWitness
|
||||
|
|
|
@ -263,7 +263,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
|||
tableView.setPlaceholder(placeholder);
|
||||
|
||||
marketColumn.setComparator(Comparator.comparing(
|
||||
o -> CurrencyUtil.getCurrencyPair(o.getOffer().getCurrencyCode()),
|
||||
o -> CurrencyUtil.getCurrencyPair(o.getOffer().getCounterCurrencyCode()),
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())
|
||||
));
|
||||
|
||||
|
@ -677,7 +677,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
|||
Optional<PaymentAccount> 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<R extends GridPane, M extends OfferBookViewM
|
|||
public void updateItem(final OfferBookListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty)
|
||||
setText(CurrencyUtil.getCurrencyPair(item.getOffer().getCurrencyCode()));
|
||||
setText(CurrencyUtil.getCurrencyPair(item.getOffer().getCounterCurrencyCode()));
|
||||
else
|
||||
setText("");
|
||||
}
|
||||
|
@ -947,7 +947,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
|||
} else {
|
||||
setText("");
|
||||
ColoredDecimalPlacesWithZerosText volumeBox = new ColoredDecimalPlacesWithZerosText(model.getVolumeAmount(item), model.getNumberOfDecimalsForVolume(item));
|
||||
if (model.showAllTradeCurrenciesProperty.get()) volumeBox.getChildren().add(new Label(" " + item.getOffer().getCurrencyCode()));
|
||||
if (model.showAllTradeCurrenciesProperty.get()) volumeBox.getChildren().add(new Label(" " + item.getOffer().getCounterCurrencyCode()));
|
||||
setGraphic(volumeBox);
|
||||
}
|
||||
} else {
|
||||
|
@ -987,11 +987,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
|||
if (model.isOfferBanned(offer)) {
|
||||
setGraphic(new AutoTooltipLabel(model.getPaymentMethod(item)));
|
||||
} else {
|
||||
if (offer.isXmrAutoConf()) {
|
||||
field = new HyperlinkWithIcon(model.getPaymentMethod(item), AwesomeIcon.ROCKET);
|
||||
} else {
|
||||
field = new HyperlinkWithIcon(model.getPaymentMethod(item));
|
||||
}
|
||||
field = new HyperlinkWithIcon(model.getPaymentMethod(item));
|
||||
field.setOnAction(event -> {
|
||||
offerDetailsWindow.show(offer);
|
||||
});
|
||||
|
|
|
@ -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<PaymentAccount> 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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1266,12 +1266,6 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
|
||||
@NotNull
|
||||
private String getTakeOfferLabel(Offer offer, boolean isBuyOffer) {
|
||||
return offer.isTraditionalOffer() ?
|
||||
Res.get("takeOffer.takeOfferButton", isBuyOffer ? Res.get("shared.sell") : Res.get("shared.buy")) :
|
||||
Res.get("takeOffer.takeOfferButtonCrypto",
|
||||
isBuyOffer ? Res.get("shared.buy") : Res.get("shared.sell"),
|
||||
offer.getCurrencyCode());
|
||||
return Res.get(isBuyOffer ? "takeOffer.takeOfferButton.sell" : "takeOffer.takeOfferButton.buy", offer.getCounterCurrencyCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -164,10 +164,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> 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<TakeOfferDataModel> 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<TakeOfferDataModel> 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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ public class ContractWindow extends Overlay<ContractWindow> {
|
|||
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()));
|
||||
|
|
|
@ -202,17 +202,12 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||
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<OfferDetailsWindow> {
|
|||
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<OfferDetailsWindow> {
|
|||
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<Button, BusyAnimation, Label, HBox> placeOfferTuple = addButtonBusyAnimationLabelAfterGroup(gridPane,
|
||||
++rowIndex, 1,
|
||||
|
|
|
@ -144,12 +144,12 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
|||
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<TradeDetailsWindow> {
|
|||
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"),
|
||||
|
|
|
@ -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<TradeCurrency> optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode());
|
||||
Optional<TradeCurrency> optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode());
|
||||
if (optionalTradeCurrency.isPresent() && tmpPaymentAccount != null) {
|
||||
TradeCurrency selectedTradeCurrency = optionalTradeCurrency.get();
|
||||
this.paymentAccount = PaymentAccount.fromProto(tmpPaymentAccount.toProtoMessage(), corePersistenceProtoResolver);
|
||||
|
|
|
@ -144,7 +144,7 @@ public class CloneOfferView extends MutableOfferView<CloneOfferViewModel> {
|
|||
model.applyOpenOffer(openOffer);
|
||||
|
||||
initWithData(openOffer.getOffer().getDirection(),
|
||||
CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode()).get(),
|
||||
CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode()).get(),
|
||||
false,
|
||||
null);
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<TradeCurrency> optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode());
|
||||
Optional<TradeCurrency> optionalTradeCurrency = CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode());
|
||||
if (optionalTradeCurrency.isPresent() && tmpPaymentAccount != null) {
|
||||
TradeCurrency selectedTradeCurrency = optionalTradeCurrency.get();
|
||||
this.paymentAccount = PaymentAccount.fromProto(tmpPaymentAccount.toProtoMessage(), corePersistenceProtoResolver);
|
||||
|
|
|
@ -141,7 +141,7 @@ public class EditOfferView extends MutableOfferView<EditOfferViewModel> {
|
|||
model.applyOpenOffer(openOffer);
|
||||
|
||||
initWithData(openOffer.getOffer().getDirection(),
|
||||
CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCurrencyCode()).get(),
|
||||
CurrencyUtil.getTradeCurrency(openOffer.getOffer().getCounterCurrencyCode()).get(),
|
||||
false,
|
||||
null);
|
||||
|
||||
|
|
|
@ -68,14 +68,14 @@ class FailedTradesViewModel extends ActivatableWithDataModel<FailedTradesDataMod
|
|||
}
|
||||
|
||||
String getDirectionLabel(FailedTradesListItem item) {
|
||||
return (item != null) ? DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getTrade().getOffer()), item.getTrade().getOffer().getCurrencyCode(), item.getTrade().getOffer().isPrivateOffer()) : "";
|
||||
return (item != null) ? DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getTrade().getOffer()), item.getTrade().getOffer().getCounterCurrencyCode(), item.getTrade().getOffer().isPrivateOffer()) : "";
|
||||
}
|
||||
|
||||
String getMarketLabel(FailedTradesListItem item) {
|
||||
if ((item == null))
|
||||
return "";
|
||||
|
||||
return CurrencyUtil.getCurrencyPair(item.getTrade().getOffer().getCurrencyCode());
|
||||
return CurrencyUtil.getCurrencyPair(item.getTrade().getOffer().getCounterCurrencyCode());
|
||||
}
|
||||
|
||||
String getDate(FailedTradesListItem item) {
|
||||
|
|
|
@ -95,6 +95,6 @@ class OpenOffersDataModel extends ActivatableDataModel {
|
|||
}
|
||||
|
||||
boolean isTriggered(OpenOffer openOffer) {
|
||||
return TriggerPriceService.isTriggered(priceFeedService.getMarketPrice(openOffer.getOffer().getCurrencyCode()), openOffer);
|
||||
return TriggerPriceService.isTriggered(priceFeedService.getMarketPrice(openOffer.getOffer().getCounterCurrencyCode()), openOffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,21 +118,21 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
|
|||
}
|
||||
|
||||
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<OpenOffersDataModel>
|
|||
if (!offer.isUseMarketBasedPrice() || triggerPrice <= 0) {
|
||||
return Res.get("shared.na");
|
||||
} else {
|
||||
return PriceUtil.formatMarketPrice(triggerPrice, offer.getCurrencyCode());
|
||||
return PriceUtil.formatMarketPrice(triggerPrice, offer.getCounterCurrencyCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ public class PendingTradesListItem implements FilterableListItem {
|
|||
}
|
||||
|
||||
public String getMarketDescription() {
|
||||
return getCurrencyPair(trade.getOffer().getCurrencyCode());
|
||||
return getCurrencyPair(trade.getOffer().getCounterCurrencyCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue