mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-10-01 01:35:48 -04:00
switch to xmr atomic units as native units
This commit is contained in:
parent
ab94b2d6fa
commit
9b4f8046b7
@ -20,6 +20,7 @@ package bisq.core.account.sign;
|
||||
import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.user.User;
|
||||
|
||||
import bisq.network.p2p.BootstrapListener;
|
||||
@ -43,6 +44,7 @@ import javax.inject.Inject;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SignatureException;
|
||||
|
||||
@ -68,7 +70,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class SignedWitnessService {
|
||||
public static final long SIGNER_AGE_DAYS = 30;
|
||||
private static final long SIGNER_AGE = SIGNER_AGE_DAYS * ChronoUnit.DAYS.getDuration().toMillis();
|
||||
public static final Coin MINIMUM_TRADE_AMOUNT_FOR_SIGNING = Coin.parseCoin("0.0025");
|
||||
public static final BigInteger MINIMUM_TRADE_AMOUNT_FOR_SIGNING = HavenoUtils.coinToAtomicUnits(Coin.parseCoin("0.0025"));
|
||||
|
||||
private final KeyRing keyRing;
|
||||
private final P2PService p2PService;
|
||||
@ -237,7 +239,7 @@ public class SignedWitnessService {
|
||||
}
|
||||
|
||||
// Arbitrators sign with EC key
|
||||
public void signAndPublishAccountAgeWitness(Coin tradeAmount,
|
||||
public void signAndPublishAccountAgeWitness(BigInteger tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
ECKey key,
|
||||
PublicKey peersPubKey) {
|
||||
@ -263,7 +265,7 @@ public class SignedWitnessService {
|
||||
}
|
||||
|
||||
// Arbitrators sign with EC key
|
||||
private String signAndPublishAccountAgeWitness(Coin tradeAmount,
|
||||
private String signAndPublishAccountAgeWitness(BigInteger tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
ECKey key,
|
||||
byte[] peersPubKey,
|
||||
@ -287,7 +289,7 @@ public class SignedWitnessService {
|
||||
key.getPubKey(),
|
||||
peersPubKey,
|
||||
time,
|
||||
tradeAmount.value);
|
||||
tradeAmount.longValueExact());
|
||||
publishSignedWitness(signedWitness);
|
||||
log.info("Arbitrator signed witness {}", signedWitness.toString());
|
||||
return "";
|
||||
@ -300,7 +302,7 @@ public class SignedWitnessService {
|
||||
}
|
||||
|
||||
// Any peer can sign with DSA key
|
||||
public Optional<SignedWitness> signAndPublishAccountAgeWitness(Coin tradeAmount,
|
||||
public Optional<SignedWitness> signAndPublishAccountAgeWitness(BigInteger tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
PublicKey peersPubKey) throws CryptoException {
|
||||
if (isSignedAccountAgeWitness(accountAgeWitness)) {
|
||||
@ -320,7 +322,7 @@ public class SignedWitnessService {
|
||||
keyRing.getSignatureKeyPair().getPublic().getEncoded(),
|
||||
peersPubKey.getEncoded(),
|
||||
new Date().getTime(),
|
||||
tradeAmount.value);
|
||||
tradeAmount.longValueExact());
|
||||
publishSignedWitness(signedWitness);
|
||||
log.info("Trader signed witness {}", signedWitness.toString());
|
||||
return Optional.of(signedWitness);
|
||||
@ -438,8 +440,8 @@ public class SignedWitnessService {
|
||||
return isSignerAccountAgeWitness(accountAgeWitness, new Date().getTime());
|
||||
}
|
||||
|
||||
public boolean isSufficientTradeAmountForSigning(Coin tradeAmount) {
|
||||
return !tradeAmount.isLessThan(MINIMUM_TRADE_AMOUNT_FOR_SIGNING);
|
||||
public boolean isSufficientTradeAmountForSigning(BigInteger tradeAmount) {
|
||||
return tradeAmount.compareTo(MINIMUM_TRADE_AMOUNT_FOR_SIGNING) >= 0;
|
||||
}
|
||||
|
||||
private boolean verifySigner(SignedWitness signedWitness) {
|
||||
|
@ -53,7 +53,6 @@ import bisq.common.util.MathUtils;
|
||||
import bisq.common.util.Tuple2;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
||||
@ -61,6 +60,7 @@ import javax.inject.Inject;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.time.Clock;
|
||||
@ -423,7 +423,7 @@ public class AccountAgeWitnessService {
|
||||
// Non fiat always has max limit
|
||||
// Account types that can get signed will use time since signing, other methods use time since account age creation
|
||||
// when measuring account age
|
||||
private long getTradeLimit(Coin maxTradeLimit,
|
||||
private BigInteger getTradeLimit(BigInteger maxTradeLimit,
|
||||
String currencyCode,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
AccountAge accountAgeCategory,
|
||||
@ -432,17 +432,17 @@ public class AccountAgeWitnessService {
|
||||
if (CurrencyUtil.isCryptoCurrency(currencyCode) ||
|
||||
!PaymentMethod.hasChargebackRisk(paymentMethod, currencyCode) ||
|
||||
direction == OfferDirection.SELL) {
|
||||
return maxTradeLimit.value;
|
||||
return maxTradeLimit;
|
||||
}
|
||||
|
||||
long limit = OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value;
|
||||
BigInteger limit = OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT;
|
||||
var factor = signedBuyFactor(accountAgeCategory);
|
||||
if (factor > 0) {
|
||||
limit = MathUtils.roundDoubleToLong(maxTradeLimit.value * factor);
|
||||
limit = BigInteger.valueOf(MathUtils.roundDoubleToLong(maxTradeLimit.longValueExact() * factor));
|
||||
}
|
||||
|
||||
log.debug("limit={}, factor={}, accountAgeWitnessHash={}",
|
||||
Coin.valueOf(limit).toFriendlyString(),
|
||||
limit,
|
||||
factor,
|
||||
Utilities.bytesAsHexString(accountAgeWitness.getHash()));
|
||||
return limit;
|
||||
@ -511,9 +511,9 @@ public class AccountAgeWitnessService {
|
||||
return 0;
|
||||
|
||||
AccountAgeWitness accountAgeWitness = getMyWitness(paymentAccount.getPaymentAccountPayload());
|
||||
Coin maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(currencyCode);
|
||||
BigInteger maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimit(currencyCode);
|
||||
if (hasTradeLimitException(accountAgeWitness)) {
|
||||
return maxTradeLimit.value;
|
||||
return maxTradeLimit.longValueExact();
|
||||
}
|
||||
final long accountSignAge = getWitnessSignAge(accountAgeWitness, new Date());
|
||||
AccountAge accountAgeCategory = getAccountAgeCategory(accountSignAge);
|
||||
@ -523,7 +523,7 @@ public class AccountAgeWitnessService {
|
||||
accountAgeWitness,
|
||||
accountAgeCategory,
|
||||
direction,
|
||||
paymentAccount.getPaymentMethod());
|
||||
paymentAccount.getPaymentMethod()).longValueExact();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -582,7 +582,7 @@ public class AccountAgeWitnessService {
|
||||
}
|
||||
|
||||
public boolean verifyPeersTradeAmount(Offer offer,
|
||||
Coin tradeAmount,
|
||||
BigInteger tradeAmount,
|
||||
ErrorMessageHandler errorMessageHandler) {
|
||||
checkNotNull(offer);
|
||||
|
||||
@ -593,8 +593,8 @@ public class AccountAgeWitnessService {
|
||||
.orElse(isToleratedSmalleAmount(tradeAmount));
|
||||
}
|
||||
|
||||
private boolean isToleratedSmalleAmount(Coin tradeAmount) {
|
||||
return tradeAmount.value <= OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value;
|
||||
private boolean isToleratedSmalleAmount(BigInteger tradeAmount) {
|
||||
return tradeAmount.longValueExact() <= OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact();
|
||||
}
|
||||
|
||||
|
||||
@ -642,14 +642,14 @@ public class AccountAgeWitnessService {
|
||||
}
|
||||
|
||||
private boolean verifyPeersTradeLimit(Offer offer,
|
||||
Coin tradeAmount,
|
||||
BigInteger tradeAmount,
|
||||
AccountAgeWitness peersWitness,
|
||||
Date peersCurrentDate,
|
||||
ErrorMessageHandler errorMessageHandler) {
|
||||
checkNotNull(offer);
|
||||
final String currencyCode = offer.getCurrencyCode();
|
||||
final Coin defaultMaxTradeLimit = offer.getPaymentMethod().getMaxTradeLimitAsCoin(currencyCode);
|
||||
long peersCurrentTradeLimit = defaultMaxTradeLimit.value;
|
||||
final BigInteger defaultMaxTradeLimit = offer.getPaymentMethod().getMaxTradeLimit(currencyCode);
|
||||
BigInteger peersCurrentTradeLimit = defaultMaxTradeLimit;
|
||||
if (!hasTradeLimitException(peersWitness)) {
|
||||
final long accountSignAge = getWitnessSignAge(peersWitness, peersCurrentDate);
|
||||
AccountAge accountAgeCategory = getPeersAccountAgeCategory(accountSignAge);
|
||||
@ -659,11 +659,11 @@ public class AccountAgeWitnessService {
|
||||
accountAgeCategory, direction, offer.getPaymentMethod());
|
||||
}
|
||||
// Makers current trade limit cannot be smaller than that in the offer
|
||||
boolean result = tradeAmount.value <= peersCurrentTradeLimit;
|
||||
boolean result = tradeAmount.longValueExact() <= peersCurrentTradeLimit.longValueExact();
|
||||
if (!result) {
|
||||
String msg = "The peers trade limit is less than the traded amount.\n" +
|
||||
"tradeAmount=" + tradeAmount.toFriendlyString() +
|
||||
"\nPeers trade limit=" + Coin.valueOf(peersCurrentTradeLimit).toFriendlyString() +
|
||||
"tradeAmount=" + tradeAmount +
|
||||
"\nPeers trade limit=" + peersCurrentTradeLimit +
|
||||
"\nOffer ID=" + offer.getShortId() +
|
||||
"\nPaymentMethod=" + offer.getPaymentMethod().getId() +
|
||||
"\nCurrencyCode=" + offer.getCurrencyCode();
|
||||
@ -698,7 +698,7 @@ public class AccountAgeWitnessService {
|
||||
// Witness signing
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void arbitratorSignAccountAgeWitness(Coin tradeAmount,
|
||||
public void arbitratorSignAccountAgeWitness(BigInteger tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
ECKey key,
|
||||
PublicKey peersPubKey) {
|
||||
@ -737,7 +737,7 @@ public class AccountAgeWitnessService {
|
||||
|
||||
public Optional<SignedWitness> traderSignAndPublishPeersAccountAgeWitness(Trade trade) {
|
||||
AccountAgeWitness peersWitness = findTradePeerWitness(trade).orElse(null);
|
||||
Coin tradeAmount = trade.getAmount();
|
||||
BigInteger tradeAmount = trade.getAmount();
|
||||
checkNotNull(trade.getTradePeer().getPubKeyRing(), "Peer must have a keyring");
|
||||
PublicKey peersPubKey = trade.getTradePeer().getPubKeyRing().getSignaturePubKey();
|
||||
checkNotNull(peersWitness, "Not able to find peers witness, unable to sign for trade {}",
|
||||
@ -800,7 +800,7 @@ public class AccountAgeWitnessService {
|
||||
}
|
||||
|
||||
private Stream<TraderDataItem> getTraderData(Dispute dispute) {
|
||||
Coin tradeAmount = dispute.getContract().getTradeAmount();
|
||||
BigInteger tradeAmount = dispute.getContract().getTradeAmount();
|
||||
|
||||
PubKeyRing buyerPubKeyRing = dispute.getContract().getBuyerPubKeyRing();
|
||||
PubKeyRing sellerPubKeyRing = dispute.getContract().getSellerPubKeyRing();
|
||||
@ -841,7 +841,7 @@ public class AccountAgeWitnessService {
|
||||
return signedWitnessService.isSignerAccountAgeWitness(accountAgeWitness);
|
||||
}
|
||||
|
||||
public boolean tradeAmountIsSufficient(Coin tradeAmount) {
|
||||
public boolean tradeAmountIsSufficient(BigInteger tradeAmount) {
|
||||
return signedWitnessService.isSufficientTradeAmountForSigning(tradeAmount);
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@ import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import bisq.proto.grpc.NotificationMessage;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -58,7 +57,7 @@ import com.google.common.util.concurrent.FutureCallback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -446,8 +445,8 @@ public class CoreApi {
|
||||
Price price,
|
||||
boolean useMarketBasedPrice,
|
||||
double marketPriceMargin,
|
||||
Coin amount,
|
||||
Coin minAmount,
|
||||
BigInteger amount,
|
||||
BigInteger minAmount,
|
||||
double buyerSecurityDeposit,
|
||||
PaymentAccount paymentAccount) {
|
||||
return coreOffersService.editOffer(offerId,
|
||||
@ -552,10 +551,6 @@ public class CoreApi {
|
||||
coreTradesService.closeTrade(tradeId);
|
||||
}
|
||||
|
||||
public void withdrawFunds(String tradeId, String address, String memo) {
|
||||
coreTradesService.withdrawFunds(tradeId, address, memo);
|
||||
}
|
||||
|
||||
public Trade getTrade(String tradeId) {
|
||||
return coreTradesService.getTrade(tradeId);
|
||||
}
|
||||
|
@ -24,8 +24,6 @@ import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.handlers.FaultHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.name.Named;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -40,6 +38,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
@ -217,33 +217,32 @@ public class CoreDisputesService {
|
||||
public void applyPayoutAmountsToDisputeResult(DisputePayout payout, Dispute dispute, DisputeResult disputeResult, long customWinnerAmount) {
|
||||
Contract contract = dispute.getContract();
|
||||
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
||||
Coin buyerSecurityDeposit = trade.getBuyerSecurityDeposit();
|
||||
Coin sellerSecurityDeposit = trade.getSellerSecurityDeposit();
|
||||
Coin tradeAmount = contract.getTradeAmount();
|
||||
BigInteger buyerSecurityDeposit = trade.getBuyerSecurityDeposit();
|
||||
BigInteger sellerSecurityDeposit = trade.getSellerSecurityDeposit();
|
||||
BigInteger tradeAmount = contract.getTradeAmount();
|
||||
if (payout == DisputePayout.BUYER_GETS_TRADE_AMOUNT) {
|
||||
disputeResult.setBuyerPayoutAmount(tradeAmount.add(buyerSecurityDeposit));
|
||||
disputeResult.setSellerPayoutAmount(sellerSecurityDeposit);
|
||||
} else if (payout == DisputePayout.BUYER_GETS_ALL) {
|
||||
disputeResult.setBuyerPayoutAmount(tradeAmount
|
||||
.add(buyerSecurityDeposit)
|
||||
.add(sellerSecurityDeposit)); // TODO (woodser): apply min payout to incentivize loser (see post v1.1.7)
|
||||
disputeResult.setSellerPayoutAmount(Coin.ZERO);
|
||||
.add(sellerSecurityDeposit)); // TODO (woodser): apply min payout to incentivize loser? (see post v1.1.7)
|
||||
disputeResult.setSellerPayoutAmount(BigInteger.valueOf(0));
|
||||
} else if (payout == DisputePayout.SELLER_GETS_TRADE_AMOUNT) {
|
||||
disputeResult.setBuyerPayoutAmount(buyerSecurityDeposit);
|
||||
disputeResult.setSellerPayoutAmount(tradeAmount.add(sellerSecurityDeposit));
|
||||
} else if (payout == DisputePayout.SELLER_GETS_ALL) {
|
||||
disputeResult.setBuyerPayoutAmount(Coin.ZERO);
|
||||
disputeResult.setBuyerPayoutAmount(BigInteger.valueOf(0));
|
||||
disputeResult.setSellerPayoutAmount(tradeAmount
|
||||
.add(sellerSecurityDeposit)
|
||||
.add(buyerSecurityDeposit));
|
||||
} else if (payout == DisputePayout.CUSTOM) {
|
||||
Coin winnerAmount = Coin.valueOf(customWinnerAmount);
|
||||
if (winnerAmount.compareTo(HavenoUtils.atomicUnitsToCoin(trade.getWallet().getBalance())) > 0) {
|
||||
if (customWinnerAmount > trade.getWallet().getBalance().longValueExact()) {
|
||||
throw new RuntimeException("The custom winner payout amount is more than the trade wallet's balance");
|
||||
}
|
||||
Coin loserAmount = tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit).minus(winnerAmount);
|
||||
disputeResult.setBuyerPayoutAmount(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? winnerAmount : loserAmount);
|
||||
disputeResult.setSellerPayoutAmount(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? loserAmount : winnerAmount);
|
||||
long loserAmount = tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit).subtract(BigInteger.valueOf(customWinnerAmount)).longValueExact();
|
||||
disputeResult.setBuyerPayoutAmount(BigInteger.valueOf(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? customWinnerAmount : loserAmount));
|
||||
disputeResult.setSellerPayoutAmount(BigInteger.valueOf(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? loserAmount : customWinnerAmount));
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,7 +253,7 @@ public class CoreDisputesService {
|
||||
String agentNodeAddress = checkNotNull(disputeManager.getAgentNodeAddress(dispute)).getFullAddress();
|
||||
Contract contract = dispute.getContract();
|
||||
String currencyCode = contract.getOfferPayload().getCurrencyCode();
|
||||
String amount = formatter.formatCoinWithCode(contract.getTradeAmount());
|
||||
String amount = HavenoUtils.formatToXmrWithCode(contract.getTradeAmount());
|
||||
|
||||
String textToSign = Res.get("disputeSummaryWindow.close.msg",
|
||||
FormattingUtils.formatDateTime(disputeResult.getCloseDate(), true),
|
||||
@ -264,8 +263,8 @@ public class CoreDisputesService {
|
||||
currencyCode,
|
||||
Res.get("disputeSummaryWindow.reason." + reason.name()),
|
||||
amount,
|
||||
formatter.formatCoinWithCode(disputeResult.getBuyerPayoutAmount()),
|
||||
formatter.formatCoinWithCode(disputeResult.getSellerPayoutAmount()),
|
||||
HavenoUtils.formatToXmrWithCode(disputeResult.getBuyerPayoutAmount()),
|
||||
HavenoUtils.formatToXmrWithCode(disputeResult.getSellerPayoutAmount()),
|
||||
disputeResult.summaryNotesProperty().get()
|
||||
);
|
||||
|
||||
|
@ -41,6 +41,7 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
@ -181,8 +182,8 @@ public class CoreOffersService {
|
||||
String offerId = createOfferService.getRandomOfferId();
|
||||
OfferDirection direction = OfferDirection.valueOf(directionAsString.toUpperCase());
|
||||
Price price = priceAsString.isEmpty() ? null : Price.valueOf(upperCaseCurrencyCode, priceStringToLong(priceAsString, upperCaseCurrencyCode));
|
||||
Coin amount = Coin.valueOf(amountAsLong);
|
||||
Coin minAmount = Coin.valueOf(minAmountAsLong);
|
||||
BigInteger amount = BigInteger.valueOf(amountAsLong);
|
||||
BigInteger minAmount = BigInteger.valueOf(minAmountAsLong);
|
||||
Coin useDefaultTxFee = Coin.ZERO;
|
||||
Offer offer = createOfferService.createAndGetOffer(offerId,
|
||||
direction,
|
||||
@ -214,8 +215,8 @@ public class CoreOffersService {
|
||||
Price price,
|
||||
boolean useMarketBasedPrice,
|
||||
double marketPriceMargin,
|
||||
Coin amount,
|
||||
Coin minAmount,
|
||||
BigInteger amount,
|
||||
BigInteger minAmount,
|
||||
double buyerSecurityDeposit,
|
||||
PaymentAccount paymentAccount) {
|
||||
Coin useDefaultTxFee = Coin.ZERO;
|
||||
|
@ -25,6 +25,7 @@ import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferBookService;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -111,7 +112,7 @@ class CorePriceService {
|
||||
for(Offer offer: buyOffers) {
|
||||
Price price = offer.getPrice();
|
||||
if (price != null) {
|
||||
double amount = (double) offer.getAmount().value / LongMath.pow(10, offer.getAmount().smallestUnitExponent());
|
||||
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);
|
||||
@ -124,7 +125,7 @@ class CorePriceService {
|
||||
for(Offer offer: sellOffers){
|
||||
Price price = offer.getPrice();
|
||||
if (price != null) {
|
||||
double amount = (double) offer.getAmount().value / LongMath.pow(10, offer.getAmount().smallestUnitExponent());
|
||||
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);
|
||||
|
@ -50,6 +50,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import static bisq.core.btc.model.AddressEntry.Context.TRADE_PAYOUT;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
class CoreTradesService {
|
||||
@ -103,8 +105,8 @@ class CoreTradesService {
|
||||
var useSavingsWallet = true;
|
||||
|
||||
// synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model
|
||||
Coin takerFee;
|
||||
Coin fundsNeededForTrade;
|
||||
BigInteger takerFee;
|
||||
BigInteger fundsNeededForTrade;
|
||||
synchronized (takeOfferModel) {
|
||||
takeOfferModel.initModel(offer, paymentAccount, useSavingsWallet);
|
||||
takerFee = takeOfferModel.getTakerFee();
|
||||
@ -164,47 +166,6 @@ class CoreTradesService {
|
||||
tradeManager.onTradeCompleted(trade);
|
||||
}
|
||||
|
||||
void withdrawFunds(String tradeId, String toAddress, String memo) {
|
||||
coreWalletsService.verifyWalletsAreAvailable();
|
||||
coreWalletsService.verifyEncryptedWalletIsUnlocked();
|
||||
|
||||
verifyTradeIsNotClosed(tradeId);
|
||||
var trade = getOpenTrade(tradeId).orElseThrow(() ->
|
||||
new IllegalArgumentException(format("trade with id '%s' not found", tradeId)));
|
||||
|
||||
verifyIsValidBTCAddress(toAddress);
|
||||
|
||||
var fromAddressEntry = btcWalletService.getOrCreateAddressEntry(trade.getId(), TRADE_PAYOUT);
|
||||
verifyFundsNotWithdrawn(fromAddressEntry);
|
||||
|
||||
var amount = trade.getPayoutAmount();
|
||||
var fee = getEstimatedTxFee(fromAddressEntry.getAddressString(), toAddress, amount);
|
||||
var receiverAmount = amount.subtract(fee);
|
||||
|
||||
log.info(format("Withdrawing funds received from trade %s:"
|
||||
+ "%n From %s%n To %s%n Amt %s%n Tx Fee %s%n Receiver Amt %s%n Memo %s%n",
|
||||
tradeId,
|
||||
fromAddressEntry.getAddressString(),
|
||||
toAddress,
|
||||
amount.toFriendlyString(),
|
||||
fee.toFriendlyString(),
|
||||
receiverAmount.toFriendlyString(),
|
||||
memo));
|
||||
tradeManager.onWithdrawRequest(
|
||||
toAddress,
|
||||
amount,
|
||||
fee,
|
||||
coreWalletsService.getKey(),
|
||||
trade,
|
||||
memo.isEmpty() ? null : memo,
|
||||
() -> {
|
||||
},
|
||||
(errorMessage, throwable) -> {
|
||||
log.error(errorMessage, throwable);
|
||||
throw new IllegalStateException(errorMessage, throwable);
|
||||
});
|
||||
}
|
||||
|
||||
String getTradeRole(String tradeId) {
|
||||
coreWalletsService.verifyWalletsAreAvailable();
|
||||
coreWalletsService.verifyEncryptedWalletIsUnlocked();
|
||||
|
@ -21,7 +21,6 @@ import bisq.core.api.model.builder.OfferInfoBuilder;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.common.Payload;
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
import java.util.Optional;
|
||||
@ -151,14 +150,14 @@ public class OfferInfo implements Payload {
|
||||
.withPrice(preciseOfferPrice)
|
||||
.withUseMarketBasedPrice(offer.isUseMarketBasedPrice())
|
||||
.withMarketPriceMarginPct(marketPriceMarginAsPctLiteral)
|
||||
.withAmount(HavenoUtils.centinerosToAtomicUnits(offer.getAmount().value).longValueExact())
|
||||
.withMinAmount(HavenoUtils.centinerosToAtomicUnits(offer.getMinAmount().value).longValueExact())
|
||||
.withAmount(offer.getAmount().longValueExact())
|
||||
.withMinAmount(offer.getMinAmount().longValueExact())
|
||||
.withVolume(roundedVolume)
|
||||
.withMinVolume(roundedMinVolume)
|
||||
.withMakerFee(HavenoUtils.centinerosToAtomicUnits(offer.getMakerFee().value).longValueExact())
|
||||
.withMakerFee(offer.getMakerFee().longValueExact())
|
||||
.withOfferFeePaymentTxId(offer.getOfferFeePaymentTxId())
|
||||
.withBuyerSecurityDeposit(HavenoUtils.centinerosToAtomicUnits(offer.getBuyerSecurityDeposit().value).longValueExact())
|
||||
.withSellerSecurityDeposit(HavenoUtils.centinerosToAtomicUnits(offer.getSellerSecurityDeposit().value).longValueExact())
|
||||
.withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().longValueExact())
|
||||
.withSellerSecurityDeposit(offer.getSellerSecurityDeposit().longValueExact())
|
||||
.withPaymentAccountId(offer.getMakerPaymentAccountId())
|
||||
.withPaymentMethodId(offer.getPaymentMethod().getId())
|
||||
.withPaymentMethodShortName(offer.getPaymentMethod().getShortName())
|
||||
|
@ -161,8 +161,8 @@ public class TradeInfo implements Payload {
|
||||
.withTakerDepositTxId(trade.getTaker().getDepositTxHash())
|
||||
.withPayoutTxId(trade.getPayoutTxId())
|
||||
.withAmountAsLong(trade.getAmountAsLong())
|
||||
.withBuyerSecurityDeposit(trade.getBuyerSecurityDeposit() == null ? -1 : trade.getBuyerSecurityDeposit().value)
|
||||
.withSellerSecurityDeposit(trade.getSellerSecurityDeposit() == null ? -1 : trade.getSellerSecurityDeposit().value)
|
||||
.withBuyerSecurityDeposit(trade.getBuyerSecurityDeposit() == null ? -1 : trade.getBuyerSecurityDeposit().longValueExact())
|
||||
.withSellerSecurityDeposit(trade.getSellerSecurityDeposit() == null ? -1 : trade.getSellerSecurityDeposit().longValueExact())
|
||||
.withPrice(toPreciseTradePrice.apply(trade))
|
||||
.withVolume(toRoundedVolume.apply(trade))
|
||||
.withArbitratorNodeAddress(toArbitratorNodeAddress.apply(trade))
|
||||
|
@ -18,18 +18,21 @@
|
||||
package bisq.core.btc.wallet;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
public class Restrictions {
|
||||
private static Coin MIN_TRADE_AMOUNT;
|
||||
private static Coin MIN_BUYER_SECURITY_DEPOSIT;
|
||||
private static BigInteger MIN_TRADE_AMOUNT;
|
||||
private static BigInteger MIN_BUYER_SECURITY_DEPOSIT;
|
||||
// For the seller we use a fixed one as there is no way the seller can cancel the trade
|
||||
// To make it editable would just increase complexity.
|
||||
private static Coin SELLER_SECURITY_DEPOSIT;
|
||||
private static BigInteger SELLER_SECURITY_DEPOSIT;
|
||||
// At mediation we require a min. payout to the losing party to keep incentive for the trader to accept the
|
||||
// mediated payout. For Refund agent cases we do not have that restriction.
|
||||
private static Coin MIN_REFUND_AT_MEDIATED_DISPUTE;
|
||||
private static BigInteger MIN_REFUND_AT_MEDIATED_DISPUTE;
|
||||
|
||||
public static Coin getMinNonDustOutput() {
|
||||
if (minNonDustOutput == null)
|
||||
@ -47,9 +50,9 @@ public class Restrictions {
|
||||
return !isAboveDust(amount);
|
||||
}
|
||||
|
||||
public static Coin getMinTradeAmount() {
|
||||
public static BigInteger getMinTradeAmount() {
|
||||
if (MIN_TRADE_AMOUNT == null)
|
||||
MIN_TRADE_AMOUNT = Coin.valueOf(10_000); // 0,7 USD @ 7000 USD/BTC
|
||||
MIN_TRADE_AMOUNT = HavenoUtils.centinerosToAtomicUnits(10000); // TODO: increase for xmr
|
||||
return MIN_TRADE_AMOUNT;
|
||||
}
|
||||
|
||||
@ -67,9 +70,9 @@ public class Restrictions {
|
||||
|
||||
// We use MIN_BUYER_SECURITY_DEPOSIT as well as lower bound in case of small trade amounts.
|
||||
// So 0.0005 BTC is the min. buyer security deposit even with amount of 0.0001 BTC and 0.05% percentage value.
|
||||
public static Coin getMinBuyerSecurityDepositAsCoin() {
|
||||
public static BigInteger getMinBuyerSecurityDeposit() {
|
||||
if (MIN_BUYER_SECURITY_DEPOSIT == null)
|
||||
MIN_BUYER_SECURITY_DEPOSIT = Coin.parseCoin("0.001"); // 0.001 BTC is 60 USD @ 60000 USD/BTC
|
||||
MIN_BUYER_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.001); // TODO: increase for xmr
|
||||
return MIN_BUYER_SECURITY_DEPOSIT;
|
||||
}
|
||||
|
||||
@ -78,16 +81,16 @@ public class Restrictions {
|
||||
return 0.15; // 15% of trade amount.
|
||||
}
|
||||
|
||||
public static Coin getMinSellerSecurityDepositAsCoin() {
|
||||
public static BigInteger getMinSellerSecurityDeposit() {
|
||||
if (SELLER_SECURITY_DEPOSIT == null)
|
||||
SELLER_SECURITY_DEPOSIT = Coin.parseCoin("0.001"); // 0.001 BTC is 60 USD @ 60000 USD/BTC
|
||||
SELLER_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.001);
|
||||
return SELLER_SECURITY_DEPOSIT;
|
||||
}
|
||||
|
||||
// This value must be lower than MIN_BUYER_SECURITY_DEPOSIT and SELLER_SECURITY_DEPOSIT
|
||||
public static Coin getMinRefundAtMediatedDispute() {
|
||||
public static BigInteger getMinRefundAtMediatedDispute() {
|
||||
if (MIN_REFUND_AT_MEDIATED_DISPUTE == null)
|
||||
MIN_REFUND_AT_MEDIATED_DISPUTE = Coin.parseCoin("0.0005"); // 0.0005 BTC is 30 USD @ 60000 USD/BTC
|
||||
MIN_REFUND_AT_MEDIATED_DISPUTE = HavenoUtils.xmrToAtomicUnits(0.0005);
|
||||
return MIN_REFUND_AT_MEDIATED_DISPUTE;
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,6 @@ import monero.wallet.model.MoneroTxWallet;
|
||||
import monero.wallet.model.MoneroWalletConfig;
|
||||
import monero.wallet.model.MoneroWalletListener;
|
||||
import monero.wallet.model.MoneroWalletListenerI;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -314,9 +313,9 @@ public class XmrWalletService {
|
||||
public MoneroTxWallet createDepositTx(Trade trade) {
|
||||
Offer offer = trade.getProcessModel().getOffer();
|
||||
String multisigAddress = trade.getProcessModel().getMultisigAddress();
|
||||
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(trade instanceof MakerTrade ? trade.getOffer().getMakerFee() : trade.getTakerFee());
|
||||
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(trade instanceof BuyerTrade ? Coin.ZERO : offer.getAmount());
|
||||
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(trade instanceof BuyerTrade ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit());
|
||||
BigInteger tradeFee = trade instanceof MakerTrade ? trade.getOffer().getMakerFee() : trade.getTakerFee();
|
||||
BigInteger sendAmount = trade instanceof BuyerTrade ? BigInteger.valueOf(0) : offer.getAmount();
|
||||
BigInteger securityDeposit = trade instanceof BuyerTrade ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
||||
|
||||
// thaw reserved outputs then create deposit tx
|
||||
MoneroWallet wallet = getWallet();
|
||||
@ -683,13 +682,13 @@ public class XmrWalletService {
|
||||
|
||||
private void notifyBalanceListeners() {
|
||||
for (XmrBalanceListener balanceListener : balanceListeners) {
|
||||
Coin balance;
|
||||
BigInteger balance;
|
||||
if (balanceListener.getSubaddressIndex() != null && balanceListener.getSubaddressIndex() != 0) balance = getBalanceForSubaddress(balanceListener.getSubaddressIndex());
|
||||
else balance = getAvailableBalance();
|
||||
UserThread.execute(new Runnable() { // TODO (woodser): don't execute on UserThread
|
||||
@Override
|
||||
public void run() {
|
||||
balanceListener.onBalanceChanged(BigInteger.valueOf(balance.value));
|
||||
balanceListener.onBalanceChanged(balance);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -847,7 +846,7 @@ public class XmrWalletService {
|
||||
}
|
||||
|
||||
public List<XmrAddressEntry> getFundedAvailableAddressEntries() {
|
||||
return getAvailableAddressEntries().stream().filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).isPositive()).collect(Collectors.toList());
|
||||
return getAvailableAddressEntries().stream().filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.valueOf(0)) > 0).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<XmrAddressEntry> getAddressEntryListAsImmutableList() {
|
||||
@ -895,31 +894,31 @@ public class XmrWalletService {
|
||||
.setIncludeOutputs(true));
|
||||
}
|
||||
|
||||
public Coin getBalanceForAddress(String address) {
|
||||
public BigInteger getBalanceForAddress(String address) {
|
||||
return getBalanceForSubaddress(wallet.getAddressIndex(address).getIndex());
|
||||
}
|
||||
|
||||
public Coin getBalanceForSubaddress(int subaddressIndex) {
|
||||
return HavenoUtils.atomicUnitsToCoin(wallet.getBalance(0, subaddressIndex));
|
||||
public BigInteger getBalanceForSubaddress(int subaddressIndex) {
|
||||
return wallet.getBalance(0, subaddressIndex);
|
||||
}
|
||||
|
||||
public Coin getAvailableBalanceForSubaddress(int subaddressIndex) {
|
||||
return HavenoUtils.atomicUnitsToCoin(wallet.getUnlockedBalance(0, subaddressIndex));
|
||||
public BigInteger getAvailableBalanceForSubaddress(int subaddressIndex) {
|
||||
return wallet.getUnlockedBalance(0, subaddressIndex);
|
||||
}
|
||||
|
||||
public Coin getBalance() {
|
||||
return wallet != null ? HavenoUtils.atomicUnitsToCoin(wallet.getBalance(0)) : Coin.ZERO;
|
||||
public BigInteger getBalance() {
|
||||
return wallet != null ? wallet.getBalance(0) : BigInteger.valueOf(0);
|
||||
}
|
||||
|
||||
public Coin getAvailableBalance() {
|
||||
return wallet != null ? HavenoUtils.atomicUnitsToCoin(wallet.getUnlockedBalance(0)) : Coin.ZERO;
|
||||
public BigInteger getAvailableBalance() {
|
||||
return wallet != null ? wallet.getUnlockedBalance(0) : BigInteger.valueOf(0);
|
||||
}
|
||||
|
||||
public Stream<XmrAddressEntry> getAddressEntriesForAvailableBalanceStream() {
|
||||
Stream<XmrAddressEntry> availableAndPayout = Stream.concat(getAddressEntries(XmrAddressEntry.Context.TRADE_PAYOUT).stream(), getFundedAvailableAddressEntries().stream());
|
||||
Stream<XmrAddressEntry> available = Stream.concat(availableAndPayout, getAddressEntries(XmrAddressEntry.Context.ARBITRATOR).stream());
|
||||
available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).stream());
|
||||
return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).isPositive());
|
||||
return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.valueOf(0)) > 0);
|
||||
}
|
||||
|
||||
public void addWalletListener(MoneroWalletListenerI listener) {
|
||||
|
@ -18,11 +18,12 @@
|
||||
package bisq.core.monetary;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Monetary;
|
||||
import org.bitcoinj.utils.ExchangeRate;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
@ -33,7 +34,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Bitcoin price value with variable precision.
|
||||
* Monero price value with variable precision.
|
||||
* <p>
|
||||
* <br/>
|
||||
* We wrap an object implementing the {@link Monetary} interface from bitcoinj. We respect the
|
||||
@ -82,23 +83,23 @@ public class Price extends MonetaryWrapper implements Comparable<Price> {
|
||||
}
|
||||
}
|
||||
|
||||
public Volume getVolumeByAmount(Coin amount) {
|
||||
public Volume getVolumeByAmount(BigInteger amount) {
|
||||
if (monetary instanceof Fiat)
|
||||
return new Volume(new ExchangeRate((Fiat) monetary).coinToFiat(amount));
|
||||
return new Volume(new ExchangeRate((Fiat) monetary).coinToFiat(HavenoUtils.atomicUnitsToCoin(amount)));
|
||||
else if (monetary instanceof Altcoin)
|
||||
return new Volume(new AltcoinExchangeRate((Altcoin) monetary).coinToAltcoin(amount));
|
||||
return new Volume(new AltcoinExchangeRate((Altcoin) monetary).coinToAltcoin(HavenoUtils.atomicUnitsToCoin(amount)));
|
||||
else
|
||||
throw new IllegalStateException("Monetary must be either of type Fiat or Altcoin");
|
||||
}
|
||||
|
||||
public Coin getAmountByVolume(Volume volume) {
|
||||
public BigInteger getAmountByVolume(Volume volume) {
|
||||
Monetary monetary = volume.getMonetary();
|
||||
if (monetary instanceof Fiat && this.monetary instanceof Fiat)
|
||||
return new ExchangeRate((Fiat) this.monetary).fiatToCoin((Fiat) monetary);
|
||||
return HavenoUtils.coinToAtomicUnits(new ExchangeRate((Fiat) this.monetary).fiatToCoin((Fiat) monetary));
|
||||
else if (monetary instanceof Altcoin && this.monetary instanceof Altcoin)
|
||||
return new AltcoinExchangeRate((Altcoin) this.monetary).altcoinToCoin((Altcoin) monetary);
|
||||
return HavenoUtils.coinToAtomicUnits(new AltcoinExchangeRate((Altcoin) this.monetary).altcoinToCoin((Altcoin) monetary));
|
||||
else
|
||||
return Coin.ZERO;
|
||||
return BigInteger.valueOf(0);
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
|
@ -45,6 +45,7 @@ import org.bitcoinj.core.Coin;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -104,8 +105,8 @@ public class CreateOfferService {
|
||||
public Offer createAndGetOffer(String offerId,
|
||||
OfferDirection direction,
|
||||
String currencyCode,
|
||||
Coin amount,
|
||||
Coin minAmount,
|
||||
BigInteger amount,
|
||||
BigInteger minAmount,
|
||||
Price price,
|
||||
Coin txFee,
|
||||
boolean useMarketBasedPrice,
|
||||
@ -128,8 +129,8 @@ public class CreateOfferService {
|
||||
price == null ? null : price.getValue(),
|
||||
useMarketBasedPrice,
|
||||
marketPriceMargin,
|
||||
amount.value,
|
||||
minAmount.value,
|
||||
amount,
|
||||
minAmount,
|
||||
buyerSecurityDepositAsDouble);
|
||||
|
||||
long creationTime = new Date().getTime();
|
||||
@ -146,8 +147,8 @@ public class CreateOfferService {
|
||||
|
||||
long priceAsLong = price != null ? price.getValue() : 0L;
|
||||
double marketPriceMarginParam = useMarketBasedPriceValue ? marketPriceMargin : 0;
|
||||
long amountAsLong = amount != null ? amount.getValue() : 0L;
|
||||
long minAmountAsLong = minAmount != null ? minAmount.getValue() : 0L;
|
||||
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;
|
||||
@ -155,10 +156,10 @@ public class CreateOfferService {
|
||||
List<String> acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount);
|
||||
String bankId = PaymentAccountUtil.getBankId(paymentAccount);
|
||||
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
|
||||
double sellerSecurityDeposit = getSellerSecurityDepositAsDouble(buyerSecurityDepositAsDouble);
|
||||
Coin makerFeeAsCoin = HavenoUtils.getMakerFee(amount);
|
||||
Coin buyerSecurityDepositAsCoin = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble);
|
||||
Coin sellerSecurityDepositAsCoin = getSellerSecurityDeposit(amount, sellerSecurityDeposit);
|
||||
double sellerSecurityDepositAsDouble = getSellerSecurityDepositAsDouble(buyerSecurityDepositAsDouble);
|
||||
BigInteger makerFee = HavenoUtils.getMakerFee(amount);
|
||||
BigInteger buyerSecurityDeposit = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble);
|
||||
BigInteger sellerSecurityDeposit = getSellerSecurityDeposit(amount, sellerSecurityDepositAsDouble);
|
||||
long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction);
|
||||
long maxTradePeriod = paymentAccount.getMaxTradePeriod();
|
||||
|
||||
@ -178,7 +179,7 @@ public class CreateOfferService {
|
||||
buyerSecurityDepositAsDouble,
|
||||
paymentAccount,
|
||||
currencyCode,
|
||||
makerFeeAsCoin);
|
||||
makerFee);
|
||||
|
||||
OfferPayload offerPayload = new OfferPayload(offerId,
|
||||
creationTime,
|
||||
@ -201,9 +202,9 @@ public class CreateOfferService {
|
||||
acceptedBanks,
|
||||
Version.VERSION,
|
||||
xmrWalletService.getWallet().getHeight(),
|
||||
makerFeeAsCoin.value,
|
||||
buyerSecurityDepositAsCoin.value,
|
||||
sellerSecurityDepositAsCoin.value,
|
||||
makerFee.longValueExact(),
|
||||
buyerSecurityDeposit.longValueExact(),
|
||||
sellerSecurityDeposit.longValueExact(),
|
||||
maxTradeLimit,
|
||||
maxTradePeriod,
|
||||
useAutoClose,
|
||||
@ -222,12 +223,12 @@ public class CreateOfferService {
|
||||
return offer;
|
||||
}
|
||||
|
||||
public Coin getReservedFundsForOffer(OfferDirection direction,
|
||||
Coin amount,
|
||||
public BigInteger getReservedFundsForOffer(OfferDirection direction,
|
||||
BigInteger amount,
|
||||
double buyerSecurityDeposit,
|
||||
double sellerSecurityDeposit) {
|
||||
|
||||
Coin reservedFundsForOffer = getSecurityDeposit(direction,
|
||||
BigInteger reservedFundsForOffer = getSecurityDeposit(direction,
|
||||
amount,
|
||||
buyerSecurityDeposit,
|
||||
sellerSecurityDeposit);
|
||||
@ -237,8 +238,8 @@ public class CreateOfferService {
|
||||
return reservedFundsForOffer;
|
||||
}
|
||||
|
||||
public Coin getSecurityDeposit(OfferDirection direction,
|
||||
Coin amount,
|
||||
public BigInteger getSecurityDeposit(OfferDirection direction,
|
||||
BigInteger amount,
|
||||
double buyerSecurityDeposit,
|
||||
double sellerSecurityDeposit) {
|
||||
return offerUtil.isBuyOffer(direction) ?
|
||||
@ -260,26 +261,25 @@ public class CreateOfferService {
|
||||
return marketPrice != null && marketPrice.isExternallyProvidedPrice();
|
||||
}
|
||||
|
||||
private Coin getBuyerSecurityDeposit(Coin amount, double buyerSecurityDeposit) {
|
||||
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(buyerSecurityDeposit, amount);
|
||||
return getBoundedBuyerSecurityDeposit(percentOfAmountAsCoin);
|
||||
private BigInteger getBuyerSecurityDeposit(BigInteger amount, double buyerSecurityDeposit) {
|
||||
BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(buyerSecurityDeposit, amount);
|
||||
return getBoundedBuyerSecurityDeposit(percentOfAmount);
|
||||
}
|
||||
|
||||
private Coin getSellerSecurityDeposit(Coin amount, double sellerSecurityDeposit) {
|
||||
Coin amountAsCoin = (amount == null) ? Coin.ZERO : amount;
|
||||
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(sellerSecurityDeposit, amountAsCoin);
|
||||
return getBoundedSellerSecurityDeposit(percentOfAmountAsCoin);
|
||||
private BigInteger getSellerSecurityDeposit(BigInteger amount, double sellerSecurityDeposit) {
|
||||
BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(sellerSecurityDeposit, amount);
|
||||
return getBoundedSellerSecurityDeposit(percentOfAmount);
|
||||
}
|
||||
|
||||
private Coin getBoundedBuyerSecurityDeposit(Coin value) {
|
||||
private BigInteger getBoundedBuyerSecurityDeposit(BigInteger value) {
|
||||
// We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the
|
||||
// MinBuyerSecurityDepositAsCoin from Restrictions.
|
||||
return Coin.valueOf(Math.max(Restrictions.getMinBuyerSecurityDepositAsCoin().value, value.value));
|
||||
// MinBuyerSecurityDeposit from Restrictions.
|
||||
return Restrictions.getMinBuyerSecurityDeposit().max(value);
|
||||
}
|
||||
|
||||
private Coin getBoundedSellerSecurityDeposit(Coin value) {
|
||||
private BigInteger getBoundedSellerSecurityDeposit(BigInteger value) {
|
||||
// We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the
|
||||
// MinSellerSecurityDepositAsCoin from Restrictions.
|
||||
return Coin.valueOf(Math.max(Restrictions.getMinSellerSecurityDepositAsCoin().value, value.value));
|
||||
// MinSellerSecurityDeposit from Restrictions.
|
||||
return Restrictions.getMinSellerSecurityDeposit().max(value);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import bisq.common.util.JsonExclude;
|
||||
import bisq.common.util.MathUtils;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
@ -49,6 +48,7 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.Date;
|
||||
@ -246,7 +246,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Volume getVolumeByAmount(Coin amount) {
|
||||
public Volume getVolumeByAmount(BigInteger amount) {
|
||||
Price price = getPrice();
|
||||
if (price == null || amount == null) {
|
||||
return null;
|
||||
@ -291,34 +291,34 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// get the amount needed for the maker to reserve the offer
|
||||
public Coin getReserveAmount() {
|
||||
Coin reserveAmount = getDirection() == OfferDirection.BUY ? getBuyerSecurityDeposit() : getSellerSecurityDeposit();
|
||||
public BigInteger getReserveAmount() {
|
||||
BigInteger reserveAmount = getDirection() == OfferDirection.BUY ? getBuyerSecurityDeposit() : getSellerSecurityDeposit();
|
||||
if (getDirection() == OfferDirection.SELL) reserveAmount = reserveAmount.add(getAmount());
|
||||
return reserveAmount;
|
||||
}
|
||||
|
||||
public Coin getMakerFee() {
|
||||
return Coin.valueOf(offerPayload.getMakerFee());
|
||||
public BigInteger getMakerFee() {
|
||||
return BigInteger.valueOf(offerPayload.getMakerFee());
|
||||
}
|
||||
|
||||
public Coin getBuyerSecurityDeposit() {
|
||||
return Coin.valueOf(offerPayload.getBuyerSecurityDeposit());
|
||||
public BigInteger getBuyerSecurityDeposit() {
|
||||
return BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit());
|
||||
}
|
||||
|
||||
public Coin getSellerSecurityDeposit() {
|
||||
return Coin.valueOf(offerPayload.getSellerSecurityDeposit());
|
||||
public BigInteger getSellerSecurityDeposit() {
|
||||
return BigInteger.valueOf(offerPayload.getSellerSecurityDeposit());
|
||||
}
|
||||
|
||||
public Coin getMaxTradeLimit() {
|
||||
return Coin.valueOf(offerPayload.getMaxTradeLimit());
|
||||
public BigInteger getMaxTradeLimit() {
|
||||
return BigInteger.valueOf(offerPayload.getMaxTradeLimit());
|
||||
}
|
||||
|
||||
public Coin getAmount() {
|
||||
return Coin.valueOf(offerPayload.getAmount());
|
||||
public BigInteger getAmount() {
|
||||
return BigInteger.valueOf(offerPayload.getAmount());
|
||||
}
|
||||
|
||||
public Coin getMinAmount() {
|
||||
return Coin.valueOf(offerPayload.getMinAmount());
|
||||
public BigInteger getMinAmount() {
|
||||
return BigInteger.valueOf(offerPayload.getMinAmount());
|
||||
}
|
||||
|
||||
public boolean isRange() {
|
||||
|
@ -208,7 +208,7 @@ public class OfferFilterService {
|
||||
.map(paymentAccount -> accountAgeWitnessService.getMyTradeLimit(paymentAccount,
|
||||
offer.getCurrencyCode(), offer.getMirroredDirection()))
|
||||
.orElse(0L);
|
||||
long offerMinAmount = offer.getMinAmount().value;
|
||||
long offerMinAmount = offer.getMinAmount().longValueExact();
|
||||
log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ",
|
||||
accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null",
|
||||
Coin.valueOf(myTradeLimit).toFriendlyString(),
|
||||
|
@ -22,14 +22,14 @@ import bisq.core.locale.Res;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.common.util.MathUtils;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -77,8 +77,8 @@ public class OfferForJson {
|
||||
|
||||
public OfferForJson(OfferDirection direction,
|
||||
String currencyCode,
|
||||
Coin minAmount,
|
||||
Coin amount,
|
||||
BigInteger minAmount,
|
||||
BigInteger amount,
|
||||
@Nullable Price price,
|
||||
Date date,
|
||||
String id,
|
||||
@ -88,8 +88,8 @@ public class OfferForJson {
|
||||
|
||||
this.direction = direction;
|
||||
this.currencyCode = currencyCode;
|
||||
this.minAmount = minAmount.value;
|
||||
this.amount = amount.value;
|
||||
this.minAmount = minAmount.longValueExact();
|
||||
this.amount = amount.longValueExact();
|
||||
this.price = price.getValue();
|
||||
this.date = date.getTime();
|
||||
this.id = id;
|
||||
@ -114,21 +114,21 @@ public class OfferForJson {
|
||||
priceDisplayString = altcoinFormat.noCode().format(price.getMonetary()).toString();
|
||||
primaryMarketMinAmountDisplayString = altcoinFormat.noCode().format(getMinVolume().getMonetary()).toString();
|
||||
primaryMarketAmountDisplayString = altcoinFormat.noCode().format(getVolume().getMonetary()).toString();
|
||||
primaryMarketMinVolumeDisplayString = coinFormat.noCode().format(getMinAmountAsCoin()).toString();
|
||||
primaryMarketVolumeDisplayString = coinFormat.noCode().format(getAmountAsCoin()).toString();
|
||||
primaryMarketMinVolumeDisplayString = HavenoUtils.formatToXmr(getMinAmount()).toString();
|
||||
primaryMarketVolumeDisplayString = HavenoUtils.formatToXmr(getAmount()).toString();
|
||||
|
||||
primaryMarketPrice = price.getValue();
|
||||
primaryMarketMinAmount = getMinVolume().getValue();
|
||||
primaryMarketAmount = getVolume().getValue();
|
||||
primaryMarketMinVolume = getMinAmountAsCoin().getValue();
|
||||
primaryMarketVolume = getAmountAsCoin().getValue();
|
||||
primaryMarketMinVolume = getMinAmount().longValueExact();
|
||||
primaryMarketVolume = getAmount().longValueExact();
|
||||
} else {
|
||||
primaryMarketDirection = direction;
|
||||
currencyPair = Res.getBaseCurrencyCode() + "/" + currencyCode;
|
||||
|
||||
priceDisplayString = fiatFormat.noCode().format(price.getMonetary()).toString();
|
||||
primaryMarketMinAmountDisplayString = coinFormat.noCode().format(getMinAmountAsCoin()).toString();
|
||||
primaryMarketAmountDisplayString = coinFormat.noCode().format(getAmountAsCoin()).toString();
|
||||
primaryMarketMinAmountDisplayString = HavenoUtils.formatToXmr(getMinAmount()).toString();
|
||||
primaryMarketAmountDisplayString = HavenoUtils.formatToXmr(getAmount()).toString();
|
||||
primaryMarketMinVolumeDisplayString = fiatFormat.noCode().format(getMinVolume().getMonetary()).toString();
|
||||
primaryMarketVolumeDisplayString = fiatFormat.noCode().format(getVolume().getMonetary()).toString();
|
||||
|
||||
@ -137,8 +137,8 @@ public class OfferForJson {
|
||||
primaryMarketMinVolume = (long) MathUtils.scaleUpByPowerOf10(getMinVolume().getValue(), 4);
|
||||
primaryMarketVolume = (long) MathUtils.scaleUpByPowerOf10(getVolume().getValue(), 4);
|
||||
|
||||
primaryMarketMinAmount = getMinAmountAsCoin().getValue();
|
||||
primaryMarketAmount = getAmountAsCoin().getValue();
|
||||
primaryMarketMinAmount = getMinAmount().longValueExact();
|
||||
primaryMarketAmount = getAmount().longValueExact();
|
||||
}
|
||||
|
||||
} catch (Throwable t) {
|
||||
@ -150,19 +150,19 @@ public class OfferForJson {
|
||||
return Price.valueOf(currencyCode, price);
|
||||
}
|
||||
|
||||
private Coin getAmountAsCoin() {
|
||||
return Coin.valueOf(amount);
|
||||
private BigInteger getAmount() {
|
||||
return BigInteger.valueOf(amount);
|
||||
}
|
||||
|
||||
private Coin getMinAmountAsCoin() {
|
||||
return Coin.valueOf(minAmount);
|
||||
private BigInteger getMinAmount() {
|
||||
return BigInteger.valueOf(minAmount);
|
||||
}
|
||||
|
||||
private Volume getVolume() {
|
||||
return getPrice().getVolumeByAmount(getAmountAsCoin());
|
||||
return getPrice().getVolumeByAmount(getAmount());
|
||||
}
|
||||
|
||||
private Volume getMinVolume() {
|
||||
return getPrice().getVolumeByAmount(getMinAmountAsCoin());
|
||||
return getPrice().getVolumeByAmount(getMinAmount());
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ import bisq.common.app.Capabilities;
|
||||
import bisq.common.app.Capability;
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.util.Utilities;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Map;
|
||||
@ -37,7 +37,7 @@ public class OfferRestrictions {
|
||||
return new Date().after(REQUIRE_TOR_NODE_ADDRESS_V3_DATE) && Config.baseCurrencyNetwork().isMainnet();
|
||||
}
|
||||
|
||||
public static Coin TOLERATED_SMALL_TRADE_AMOUNT = Coin.parseCoin("2.0");
|
||||
public static BigInteger TOLERATED_SMALL_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(2.0);
|
||||
|
||||
static boolean hasOfferMandatoryCapability(Offer offer, Capability mandatoryCapability) {
|
||||
Map<String, String> extraDataMap = offer.getExtraDataMap();
|
||||
|
@ -40,7 +40,6 @@ import bisq.common.app.Capabilities;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.util.MathUtils;
|
||||
import bisq.common.util.Utilities;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionInput;
|
||||
import org.bitcoinj.core.TransactionOutput;
|
||||
@ -49,6 +48,7 @@ import org.bitcoinj.utils.Fiat;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -129,7 +129,7 @@ public class OfferUtil {
|
||||
* @param balance a wallet balance
|
||||
* @return true if balance >= cost
|
||||
*/
|
||||
public boolean isBalanceSufficient(Coin cost, Coin balance) {
|
||||
public boolean isBalanceSufficient(BigInteger cost, BigInteger balance) {
|
||||
return cost != null && balance.compareTo(cost) >= 0;
|
||||
}
|
||||
|
||||
@ -141,16 +141,15 @@ public class OfferUtil {
|
||||
* @param balance a wallet balance
|
||||
* @return the wallet balance shortage for the given cost, else zero.
|
||||
*/
|
||||
public Coin getBalanceShortage(Coin cost, Coin balance) {
|
||||
public BigInteger getBalanceShortage(BigInteger cost, BigInteger balance) {
|
||||
if (cost != null) {
|
||||
Coin shortage = cost.subtract(balance);
|
||||
return shortage.isNegative() ? Coin.ZERO : shortage;
|
||||
BigInteger shortage = cost.subtract(balance);
|
||||
return shortage.compareTo(BigInteger.valueOf(0)) < 0 ? BigInteger.valueOf(0) : shortage;
|
||||
} else {
|
||||
return Coin.ZERO;
|
||||
return BigInteger.valueOf(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public double calculateManualPrice(double volumeAsDouble, double amountAsDouble) {
|
||||
return volumeAsDouble / amountAsDouble;
|
||||
}
|
||||
@ -163,7 +162,7 @@ public class OfferUtil {
|
||||
return offer != null && offer.getPaymentMethod().isBlockchain();
|
||||
}
|
||||
|
||||
public Optional<Volume> getFeeInUserFiatCurrency(Coin makerFee,
|
||||
public Optional<Volume> getFeeInUserFiatCurrency(BigInteger makerFee,
|
||||
CoinFormatter formatter) {
|
||||
String userCurrencyCode = preferences.getPreferredTradeCurrency().getCode();
|
||||
if (CurrencyUtil.isCryptoCurrency(userCurrencyCode)) {
|
||||
@ -216,8 +215,8 @@ public class OfferUtil {
|
||||
public void validateOfferData(double buyerSecurityDeposit,
|
||||
PaymentAccount paymentAccount,
|
||||
String currencyCode,
|
||||
Coin makerFeeAsCoin) {
|
||||
checkNotNull(makerFeeAsCoin, "makerFee must not be null");
|
||||
BigInteger makerFee) {
|
||||
checkNotNull(makerFee, "makerFee must not be null");
|
||||
checkNotNull(p2PService.getAddress(), "Address must not be null");
|
||||
checkArgument(buyerSecurityDeposit <= getMaxBuyerSecurityDepositAsPercent(),
|
||||
"securityDeposit must not exceed " +
|
||||
@ -231,7 +230,7 @@ public class OfferUtil {
|
||||
Res.get("offerbook.warning.paymentMethodBanned"));
|
||||
}
|
||||
|
||||
private Optional<Volume> getFeeInUserFiatCurrency(Coin makerFee, String userCurrencyCode, CoinFormatter formatter) {
|
||||
private Optional<Volume> getFeeInUserFiatCurrency(BigInteger makerFee, String userCurrencyCode, CoinFormatter formatter) {
|
||||
MarketPrice marketPrice = priceFeedService.getMarketPrice(userCurrencyCode);
|
||||
if (marketPrice != null && makerFee != null) {
|
||||
long marketPriceAsLong = roundDoubleToLong(scaleUpByPowerOf10(marketPrice.getPrice(), Fiat.SMALLEST_UNIT_EXPONENT));
|
||||
|
@ -73,7 +73,6 @@ import bisq.common.persistence.PersistenceManager;
|
||||
import bisq.common.proto.network.NetworkEnvelope;
|
||||
import bisq.common.proto.persistable.PersistedDataHost;
|
||||
import bisq.common.util.Tuple2;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -800,8 +799,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
}
|
||||
|
||||
// get offer reserve amount
|
||||
Coin offerReserveAmountCoin = openOffer.getOffer().getReserveAmount();
|
||||
BigInteger offerReserveAmount = HavenoUtils.centinerosToAtomicUnits(offerReserveAmountCoin.value);
|
||||
BigInteger offerReserveAmount = openOffer.getOffer().getReserveAmount();
|
||||
|
||||
// handle sufficient available balance
|
||||
if (xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0) {
|
||||
@ -814,7 +812,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
|
||||
// otherwise sign and post offer
|
||||
else {
|
||||
signAndPostOffer(openOffer, offerReserveAmountCoin, true, resultHandler, errorMessageHandler);
|
||||
signAndPostOffer(openOffer, offerReserveAmount, true, resultHandler, errorMessageHandler);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -887,7 +885,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
}
|
||||
|
||||
private void signAndPostOffer(OpenOffer openOffer,
|
||||
Coin offerReserveAmount,
|
||||
BigInteger offerReserveAmount,
|
||||
boolean useSavingsWallet, // TODO: remove this
|
||||
TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||
log.info("Signing and posting offer " + openOffer.getId());
|
||||
@ -980,8 +978,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
|
||||
// verify maker's trade fee
|
||||
Offer offer = new Offer(request.getOfferPayload());
|
||||
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(HavenoUtils.getMakerFee(offer.getAmount()));
|
||||
if (!tradeFee.equals(HavenoUtils.coinToAtomicUnits(offer.getMakerFee()))) {
|
||||
BigInteger tradeFee = HavenoUtils.getMakerFee(offer.getAmount());
|
||||
if (!tradeFee.equals(offer.getMakerFee())) {
|
||||
errorMessage = "Wrong trade fee for offer " + request.offerId;
|
||||
log.info(errorMessage);
|
||||
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage);
|
||||
@ -989,8 +987,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
}
|
||||
|
||||
// verify maker's reserve tx (double spend, trade fee, trade amount, mining fee)
|
||||
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(offer.getDirection() == OfferDirection.BUY ? Coin.ZERO : offer.getAmount());
|
||||
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit());
|
||||
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
|
||||
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
||||
MoneroTx reserveTx = xmrWalletService.verifyTradeTx(
|
||||
tradeFee,
|
||||
sendAmount,
|
||||
@ -1011,8 +1009,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
SignedOffer signedOffer = new SignedOffer(
|
||||
System.currentTimeMillis(),
|
||||
signedOfferPayload.getId(),
|
||||
HavenoUtils.coinToAtomicUnits(offer.getAmount()).longValueExact(),
|
||||
HavenoUtils.coinToAtomicUnits(HavenoUtils.getMakerFee(offer.getAmount())).longValueExact(),
|
||||
offer.getAmount().longValueExact(),
|
||||
HavenoUtils.getMakerFee(offer.getAmount()).longValueExact(),
|
||||
request.getReserveTxHash(),
|
||||
request.getReserveTxHex(),
|
||||
request.getReserveTxKeyImages(),
|
||||
|
@ -21,7 +21,6 @@ import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.offer.availability.OfferAvailabilityModel;
|
||||
import bisq.core.offer.messages.OfferAvailabilityRequest;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
@ -72,9 +71,9 @@ public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> {
|
||||
offer.getId(),
|
||||
P2PService.getMyNodeAddress(),
|
||||
p2PService.getKeyRing().getPubKeyRing(),
|
||||
offer.getAmount().value,
|
||||
offer.getAmount().longValueExact(),
|
||||
price.getValue(),
|
||||
HavenoUtils.getTakerFee(offer.getAmount()).value,
|
||||
HavenoUtils.getTakerFee(offer.getAmount()).longValueExact(),
|
||||
user.getAccountId(),
|
||||
paymentAccountId,
|
||||
paymentMethodId,
|
||||
|
@ -34,7 +34,8 @@ import bisq.common.taskrunner.Model;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import lombok.Getter;
|
||||
@ -50,7 +51,7 @@ import monero.wallet.model.MoneroTxWallet;
|
||||
public class PlaceOfferModel implements Model {
|
||||
// Immutable
|
||||
private final Offer offer;
|
||||
private final Coin reservedFundsForOffer;
|
||||
private final BigInteger reservedFundsForOffer;
|
||||
private final boolean useSavingsWallet;
|
||||
private final P2PService p2PService;
|
||||
private final BtcWalletService walletService;
|
||||
@ -78,7 +79,7 @@ public class PlaceOfferModel implements Model {
|
||||
private SignOfferResponse signOfferResponse;
|
||||
|
||||
public PlaceOfferModel(Offer offer,
|
||||
Coin reservedFundsForOffer,
|
||||
BigInteger reservedFundsForOffer,
|
||||
boolean useSavingsWallet,
|
||||
P2PService p2PService,
|
||||
BtcWalletService walletService,
|
||||
|
@ -23,14 +23,12 @@ import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.offer.placeoffer.PlaceOfferModel;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import monero.daemon.model.MoneroOutput;
|
||||
import monero.wallet.model.MoneroTxWallet;
|
||||
@ -54,9 +52,9 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||
model.getXmrWalletService().getConnectionsService().verifyConnection();
|
||||
|
||||
// create reserve tx
|
||||
BigInteger makerFee = HavenoUtils.coinToAtomicUnits(offer.getMakerFee());
|
||||
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(offer.getDirection() == OfferDirection.BUY ? Coin.ZERO : offer.getAmount());
|
||||
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit());
|
||||
BigInteger makerFee = offer.getMakerFee();
|
||||
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
|
||||
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
||||
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
|
||||
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(makerFee, sendAmount, securityDeposit, returnAddress);
|
||||
|
||||
|
@ -30,6 +30,8 @@ import org.bitcoinj.core.Coin;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class ValidateOffer extends Task<PlaceOfferModel> {
|
||||
public ValidateOffer(TaskRunner<PlaceOfferModel> taskHandler, PlaceOfferModel model) {
|
||||
super(taskHandler, model);
|
||||
@ -42,13 +44,13 @@ public class ValidateOffer extends Task<PlaceOfferModel> {
|
||||
runInterceptHook();
|
||||
|
||||
// Coins
|
||||
checkCoinNotNullOrZero(offer.getAmount(), "Amount");
|
||||
checkCoinNotNullOrZero(offer.getMinAmount(), "MinAmount");
|
||||
checkCoinNotNullOrZero(offer.getMakerFee(), "MakerFee");
|
||||
checkCoinNotNullOrZero(offer.getBuyerSecurityDeposit(), "buyerSecurityDeposit");
|
||||
checkCoinNotNullOrZero(offer.getSellerSecurityDeposit(), "sellerSecurityDeposit");
|
||||
checkBINotNullOrZero(offer.getAmount(), "Amount");
|
||||
checkBINotNullOrZero(offer.getMinAmount(), "MinAmount");
|
||||
checkBINotNullOrZero(offer.getMakerFee(), "MakerFee");
|
||||
checkBINotNullOrZero(offer.getBuyerSecurityDeposit(), "buyerSecurityDeposit");
|
||||
checkBINotNullOrZero(offer.getSellerSecurityDeposit(), "sellerSecurityDeposit");
|
||||
//checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model
|
||||
checkCoinNotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit");
|
||||
checkBINotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit");
|
||||
|
||||
// We remove those checks to be more flexible with future changes.
|
||||
/*checkArgument(offer.getMakerFee().value >= FeeService.getMinMakerFee(offer.isCurrencyForMakerFeeBtc()).value,
|
||||
@ -67,8 +69,8 @@ public class ValidateOffer extends Task<PlaceOfferModel> {
|
||||
"MinAmount is less than " + ProposalConsensus.getMinTradeAmount().toFriendlyString());*/
|
||||
|
||||
long maxAmount = model.getAccountAgeWitnessService().getMyTradeLimit(model.getUser().getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection());
|
||||
checkArgument(offer.getAmount().longValue() <= maxAmount,
|
||||
"Amount is larger than " + HavenoUtils.coinToXmr(offer.getPaymentMethod().getMaxTradeLimitAsCoin(offer.getCurrencyCode())) + " XMR");
|
||||
checkArgument(offer.getAmount().longValueExact() <= maxAmount,
|
||||
"Amount is larger than " + HavenoUtils.atomicUnitsToXmr(offer.getPaymentMethod().getMaxTradeLimit(offer.getCurrencyCode())) + " XMR");
|
||||
checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount");
|
||||
|
||||
checkNotNull(offer.getPrice(), "Price is null");
|
||||
@ -100,6 +102,12 @@ public class ValidateOffer extends Task<PlaceOfferModel> {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkBINotNullOrZero(BigInteger value, String name) {
|
||||
checkNotNull(value, name + " is null");
|
||||
checkArgument(value.compareTo(BigInteger.valueOf(0)) > 0,
|
||||
name + " must be positive. " + name + "=" + value);
|
||||
}
|
||||
|
||||
public static void checkCoinNotNullOrZero(Coin value, String name) {
|
||||
checkNotNull(value, name + " is null");
|
||||
checkArgument(value.isPositive(),
|
||||
|
@ -31,10 +31,9 @@ import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.common.taskrunner.Model;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
import lombok.Getter;
|
||||
@ -46,11 +45,8 @@ import static bisq.core.btc.model.XmrAddressEntry.Context.OFFER_FUNDING;
|
||||
import static bisq.core.offer.OfferDirection.SELL;
|
||||
import static bisq.core.util.VolumeUtil.getAdjustedVolumeForHalCash;
|
||||
import static bisq.core.util.VolumeUtil.getRoundedFiatVolume;
|
||||
import static bisq.core.util.coin.CoinUtil.minCoin;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.bitcoinj.core.Coin.ZERO;
|
||||
import static org.bitcoinj.core.Coin.valueOf;
|
||||
|
||||
@Slf4j
|
||||
public class TakeOfferModel implements Model {
|
||||
@ -64,23 +60,23 @@ public class TakeOfferModel implements Model {
|
||||
@Getter
|
||||
private XmrAddressEntry addressEntry;
|
||||
@Getter
|
||||
private Coin amount;
|
||||
private BigInteger amount;
|
||||
private Offer offer;
|
||||
private PaymentAccount paymentAccount;
|
||||
@Getter
|
||||
private Coin securityDeposit;
|
||||
private BigInteger securityDeposit;
|
||||
private boolean useSavingsWallet;
|
||||
|
||||
@Getter
|
||||
private Coin takerFee;
|
||||
private BigInteger takerFee;
|
||||
@Getter
|
||||
private Coin totalToPayAsCoin;
|
||||
private BigInteger totalToPay;
|
||||
@Getter
|
||||
private Coin missingCoin = ZERO;
|
||||
private BigInteger missingCoin = BigInteger.valueOf(0);
|
||||
@Getter
|
||||
private Coin totalAvailableBalance;
|
||||
private BigInteger totalAvailableBalance;
|
||||
@Getter
|
||||
private Coin availableBalance;
|
||||
private BigInteger availableBalance;
|
||||
@Getter
|
||||
private boolean isXmrWalletFunded;
|
||||
@Getter
|
||||
@ -107,7 +103,7 @@ public class TakeOfferModel implements Model {
|
||||
validateModelInputs();
|
||||
|
||||
this.useSavingsWallet = useSavingsWallet;
|
||||
this.amount = valueOf(Math.min(offer.getAmount().value, getMaxTradeLimit()));
|
||||
this.amount = offer.getAmount().min(BigInteger.valueOf(getMaxTradeLimit()));
|
||||
this.securityDeposit = offer.getDirection() == SELL
|
||||
? offer.getBuyerSecurityDeposit()
|
||||
: offer.getSellerSecurityDeposit();
|
||||
@ -130,9 +126,9 @@ public class TakeOfferModel implements Model {
|
||||
// maker created the offer and reserved his funds, so that would not work well
|
||||
// with dynamic fees. The mining fee for the takeOfferFee tx is deducted from
|
||||
// the createOfferFee and not visible to the trader.
|
||||
Coin feeAndSecDeposit = securityDeposit.add(takerFee);
|
||||
BigInteger feeAndSecDeposit = securityDeposit.add(takerFee);
|
||||
|
||||
totalToPayAsCoin = offer.isBuyOffer()
|
||||
totalToPay = offer.isBuyOffer()
|
||||
? feeAndSecDeposit.add(amount)
|
||||
: feeAndSecDeposit;
|
||||
|
||||
@ -155,9 +151,9 @@ public class TakeOfferModel implements Model {
|
||||
|
||||
private void updateBalance() {
|
||||
totalAvailableBalance = xmrWalletService.getAvailableBalance();
|
||||
if (totalToPayAsCoin != null) availableBalance = minCoin(totalToPayAsCoin, totalAvailableBalance);
|
||||
missingCoin = offerUtil.getBalanceShortage(totalToPayAsCoin, availableBalance);
|
||||
isXmrWalletFunded = offerUtil.isBalanceSufficient(totalToPayAsCoin, availableBalance);
|
||||
if (totalToPay != null) availableBalance = totalToPay.min(totalAvailableBalance);
|
||||
missingCoin = offerUtil.getBalanceShortage(totalToPay, availableBalance);
|
||||
isXmrWalletFunded = offerUtil.isBalanceSufficient(totalToPay, availableBalance);
|
||||
}
|
||||
|
||||
private long getMaxTradeLimit() {
|
||||
@ -167,15 +163,15 @@ public class TakeOfferModel implements Model {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Coin getFundsNeededForTrade() {
|
||||
public BigInteger getFundsNeededForTrade() {
|
||||
// If taking a buy offer, taker needs to reserve the offer.amt too.
|
||||
return securityDeposit.add(offer.isBuyOffer() ? amount : ZERO);
|
||||
return securityDeposit.add(offer.isBuyOffer() ? amount : BigInteger.valueOf(0));
|
||||
}
|
||||
|
||||
private void validateModelInputs() {
|
||||
checkNotNull(offer, "offer must not be null");
|
||||
checkNotNull(offer.getAmount(), "offer amount must not be null");
|
||||
checkArgument(offer.getAmount().value > 0, "offer amount must not be zero");
|
||||
checkArgument(offer.getAmount().longValueExact() > 0, "offer amount must not be zero");
|
||||
checkNotNull(offer.getPrice(), "offer price must not be null");
|
||||
checkNotNull(paymentAccount, "payment account must not be null");
|
||||
checkNotNull(addressEntry, "address entry must not be null");
|
||||
@ -186,13 +182,13 @@ public class TakeOfferModel implements Model {
|
||||
this.amount = null;
|
||||
this.availableBalance = null;
|
||||
this.isXmrWalletFunded = false;
|
||||
this.missingCoin = ZERO;
|
||||
this.missingCoin = BigInteger.valueOf(0);
|
||||
this.offer = null;
|
||||
this.paymentAccount = null;
|
||||
this.securityDeposit = null;
|
||||
this.takerFee = null;
|
||||
this.totalAvailableBalance = null;
|
||||
this.totalToPayAsCoin = null;
|
||||
this.totalToPay = null;
|
||||
this.useSavingsWallet = true;
|
||||
this.volume = null;
|
||||
}
|
||||
@ -209,7 +205,7 @@ public class TakeOfferModel implements Model {
|
||||
", amount=" + amount + "\n" +
|
||||
", securityDeposit=" + securityDeposit + "\n" +
|
||||
", takerFee=" + takerFee + "\n" +
|
||||
", totalToPayAsCoin=" + totalToPayAsCoin + "\n" +
|
||||
", totalToPay=" + totalToPay + "\n" +
|
||||
", missingCoin=" + missingCoin + "\n" +
|
||||
", totalAvailableBalance=" + totalAvailableBalance + "\n" +
|
||||
", availableBalance=" + availableBalance + "\n" +
|
||||
|
@ -71,7 +71,7 @@ public class PaymentAccountUtil {
|
||||
AccountAgeWitnessService accountAgeWitnessService) {
|
||||
boolean hasChargebackRisk = hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode());
|
||||
boolean hasValidAccountAgeWitness = accountAgeWitnessService.getMyTradeLimit(paymentAccount,
|
||||
offer.getCurrencyCode(), offer.getMirroredDirection()) >= offer.getMinAmount().value;
|
||||
offer.getCurrencyCode(), offer.getMirroredDirection()) >= offer.getMinAmount().longValueExact();
|
||||
return !hasChargebackRisk || hasValidAccountAgeWitness;
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,7 @@
|
||||
package bisq.core.payment;
|
||||
|
||||
import bisq.common.util.MathUtils;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -29,12 +28,14 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class TradeLimits {
|
||||
private static final Coin MAX_TRADE_LIMIT = Coin.parseCoin("20"); // max trade limit for lowest risk payment method. Others will get derived from that.
|
||||
private static final BigInteger MAX_TRADE_LIMIT = HavenoUtils.xmrToAtomicUnits(20.0); // max trade limit for lowest risk payment method. Others will get derived from that.
|
||||
@Nullable
|
||||
@Getter
|
||||
private static TradeLimits INSTANCE;
|
||||
@ -57,7 +58,7 @@ public class TradeLimits {
|
||||
* @see bisq.core.payment.payload.PaymentMethod
|
||||
* @return the maximum trade limit
|
||||
*/
|
||||
public Coin getMaxTradeLimit() {
|
||||
public BigInteger getMaxTradeLimit() {
|
||||
return MAX_TRADE_LIMIT;
|
||||
}
|
||||
|
||||
|
@ -77,8 +77,7 @@ import bisq.common.config.BaseCurrencyNetwork;
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.proto.persistable.PersistablePayload;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -113,10 +112,10 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
||||
// risk factor so the relation between the risk categories stays the same as with the default values.
|
||||
// We must not change those values as it could lead to invalid offers if amount becomes lower then new trade limit.
|
||||
// Increasing might be ok, but needs more thought as well...
|
||||
private static final Coin DEFAULT_TRADE_LIMIT_VERY_LOW_RISK = Coin.parseCoin("100");
|
||||
private static final Coin DEFAULT_TRADE_LIMIT_LOW_RISK = Coin.parseCoin("50");
|
||||
private static final Coin DEFAULT_TRADE_LIMIT_MID_RISK = Coin.parseCoin("25");
|
||||
private static final Coin DEFAULT_TRADE_LIMIT_HIGH_RISK = Coin.parseCoin("12.5");
|
||||
private static final BigInteger DEFAULT_TRADE_LIMIT_VERY_LOW_RISK = HavenoUtils.xmrToAtomicUnits(100);
|
||||
private static final BigInteger DEFAULT_TRADE_LIMIT_LOW_RISK = HavenoUtils.xmrToAtomicUnits(50);
|
||||
private static final BigInteger DEFAULT_TRADE_LIMIT_MID_RISK = HavenoUtils.xmrToAtomicUnits(25);
|
||||
private static final BigInteger DEFAULT_TRADE_LIMIT_HIGH_RISK = HavenoUtils.xmrToAtomicUnits(12.5);
|
||||
|
||||
public static final String UPHOLD_ID = "UPHOLD";
|
||||
public static final String MONEY_BEAM_ID = "MONEY_BEAM";
|
||||
@ -291,19 +290,19 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
||||
TRANSFERWISE_USD = new PaymentMethod(TRANSFERWISE_USD_ID, 4 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(TransferwiseUsdAccount.SUPPORTED_CURRENCIES)),
|
||||
PAYSERA = new PaymentMethod(PAYSERA_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PayseraAccount.SUPPORTED_CURRENCIES)),
|
||||
PAXUM = new PaymentMethod(PAXUM_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PaxumAccount.SUPPORTED_CURRENCIES)),
|
||||
NEFT = new PaymentMethod(NEFT_ID, DAY, Coin.parseCoin("0.02"), getAssetCodes(NeftAccount.SUPPORTED_CURRENCIES)),
|
||||
NEFT = new PaymentMethod(NEFT_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.02), getAssetCodes(NeftAccount.SUPPORTED_CURRENCIES)),
|
||||
RTGS = new PaymentMethod(RTGS_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(RtgsAccount.SUPPORTED_CURRENCIES)),
|
||||
IMPS = new PaymentMethod(IMPS_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(ImpsAccount.SUPPORTED_CURRENCIES)),
|
||||
UPI = new PaymentMethod(UPI_ID, DAY, Coin.parseCoin("0.05"), getAssetCodes(UpiAccount.SUPPORTED_CURRENCIES)),
|
||||
PAYTM = new PaymentMethod(PAYTM_ID, DAY, Coin.parseCoin("0.05"), getAssetCodes(PaytmAccount.SUPPORTED_CURRENCIES)),
|
||||
UPI = new PaymentMethod(UPI_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.05), getAssetCodes(UpiAccount.SUPPORTED_CURRENCIES)),
|
||||
PAYTM = new PaymentMethod(PAYTM_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.05), getAssetCodes(PaytmAccount.SUPPORTED_CURRENCIES)),
|
||||
NEQUI = new PaymentMethod(NEQUI_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(NequiAccount.SUPPORTED_CURRENCIES)),
|
||||
BIZUM = new PaymentMethod(BIZUM_ID, DAY, Coin.parseCoin("0.04"), getAssetCodes(BizumAccount.SUPPORTED_CURRENCIES)),
|
||||
BIZUM = new PaymentMethod(BIZUM_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.04), getAssetCodes(BizumAccount.SUPPORTED_CURRENCIES)),
|
||||
PIX = new PaymentMethod(PIX_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PixAccount.SUPPORTED_CURRENCIES)),
|
||||
CAPITUAL = new PaymentMethod(CAPITUAL_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CapitualAccount.SUPPORTED_CURRENCIES)),
|
||||
CELPAY = new PaymentMethod(CELPAY_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CelPayAccount.SUPPORTED_CURRENCIES)),
|
||||
MONESE = new PaymentMethod(MONESE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(MoneseAccount.SUPPORTED_CURRENCIES)),
|
||||
SATISPAY = new PaymentMethod(SATISPAY_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(SatispayAccount.SUPPORTED_CURRENCIES)),
|
||||
TIKKIE = new PaymentMethod(TIKKIE_ID, DAY, Coin.parseCoin("0.05"), getAssetCodes(TikkieAccount.SUPPORTED_CURRENCIES)),
|
||||
TIKKIE = new PaymentMethod(TIKKIE_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.05), getAssetCodes(TikkieAccount.SUPPORTED_CURRENCIES)),
|
||||
VERSE = new PaymentMethod(VERSE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(VerseAccount.SUPPORTED_CURRENCIES)),
|
||||
STRIKE = new PaymentMethod(STRIKE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(StrikeAccount.SUPPORTED_CURRENCIES)),
|
||||
SWIFT = new PaymentMethod(SWIFT_ID, 7 * DAY, DEFAULT_TRADE_LIMIT_MID_RISK, getAssetCodes(SwiftAccount.SUPPORTED_CURRENCIES)),
|
||||
@ -365,7 +364,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
||||
}
|
||||
|
||||
public static PaymentMethod getDummyPaymentMethod(String id) {
|
||||
return new PaymentMethod(id, 0, Coin.ZERO, Arrays.asList());
|
||||
return new PaymentMethod(id, 0, BigInteger.valueOf(0), Arrays.asList());
|
||||
}
|
||||
|
||||
|
||||
@ -405,16 +404,16 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
||||
* @param maxTradeLimit The max. allowed trade amount in Bitcoin for that payment method (depending on charge back risk)
|
||||
* @param supportedAssetCodes Supported asset codes.
|
||||
*/
|
||||
private PaymentMethod(String id, long maxTradePeriod, Coin maxTradeLimit, List<String> supportedAssetCodes) {
|
||||
private PaymentMethod(String id, long maxTradePeriod, BigInteger maxTradeLimit, List<String> supportedAssetCodes) {
|
||||
this.id = id;
|
||||
this.maxTradePeriod = maxTradePeriod;
|
||||
this.maxTradeLimit = maxTradeLimit.value;
|
||||
this.maxTradeLimit = maxTradeLimit.longValueExact();
|
||||
this.supportedAssetCodes = supportedAssetCodes;
|
||||
}
|
||||
|
||||
// Used for dummy entries in payment methods list (SHOW_ALL)
|
||||
private PaymentMethod(String id) {
|
||||
this(id, 0, Coin.ZERO, new ArrayList<String>());
|
||||
this(id, 0, BigInteger.valueOf(0), new ArrayList<String>());
|
||||
}
|
||||
|
||||
|
||||
@ -435,7 +434,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
||||
public static PaymentMethod fromProto(protobuf.PaymentMethod proto) {
|
||||
return new PaymentMethod(proto.getId(),
|
||||
proto.getMaxTradePeriod(),
|
||||
Coin.valueOf(proto.getMaxTradeLimit()),
|
||||
BigInteger.valueOf(proto.getMaxTradeLimit()),
|
||||
proto.getSupportedAssetCodesList());
|
||||
}
|
||||
|
||||
@ -456,44 +455,43 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public Coin getMaxTradeLimitAsCoin(String currencyCode) {
|
||||
public BigInteger getMaxTradeLimit(String currencyCode) {
|
||||
// Hack for SF as the smallest unit is 1 SF ;-( and price is about 3 BTC!
|
||||
if (currencyCode.equals("SF"))
|
||||
return Coin.parseCoin("4");
|
||||
return HavenoUtils.xmrToAtomicUnits(4);
|
||||
// payment methods which define their own trade limits
|
||||
if (id.equals(NEFT_ID) || id.equals(UPI_ID) || id.equals(PAYTM_ID) || id.equals(BIZUM_ID) || id.equals(TIKKIE_ID)) {
|
||||
return Coin.valueOf(maxTradeLimit);
|
||||
return BigInteger.valueOf(maxTradeLimit);
|
||||
}
|
||||
|
||||
// We use the class field maxTradeLimit only for mapping the risk factor.
|
||||
long riskFactor;
|
||||
if (maxTradeLimit == DEFAULT_TRADE_LIMIT_VERY_LOW_RISK.value)
|
||||
if (maxTradeLimit == DEFAULT_TRADE_LIMIT_VERY_LOW_RISK.longValueExact())
|
||||
riskFactor = 1;
|
||||
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_LOW_RISK.value)
|
||||
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_LOW_RISK.longValueExact())
|
||||
riskFactor = 2;
|
||||
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_MID_RISK.value)
|
||||
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_MID_RISK.longValueExact())
|
||||
riskFactor = 4;
|
||||
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_HIGH_RISK.value)
|
||||
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_HIGH_RISK.longValueExact())
|
||||
riskFactor = 8;
|
||||
else {
|
||||
riskFactor = 8;
|
||||
log.warn("maxTradeLimit is not matching one of our default values. We use highest risk factor. " +
|
||||
"maxTradeLimit={}. PaymentMethod={}",
|
||||
Coin.valueOf(maxTradeLimit).toFriendlyString(), this);
|
||||
"maxTradeLimit={}. PaymentMethod={}", maxTradeLimit, this);
|
||||
}
|
||||
|
||||
// get risk based trade limit
|
||||
TradeLimits tradeLimits = new TradeLimits();
|
||||
long maxTradeLimit = tradeLimits.getMaxTradeLimit().value;
|
||||
long riskBasedTradeLimit = tradeLimits.getRoundedRiskBasedTradeLimit(maxTradeLimit, riskFactor); // as centineros
|
||||
long maxTradeLimit = tradeLimits.getMaxTradeLimit().longValueExact();
|
||||
long riskBasedTradeLimit = tradeLimits.getRoundedRiskBasedTradeLimit(maxTradeLimit, riskFactor);
|
||||
|
||||
// if fiat and stagenet, cap offer amounts to avoid offers which cannot be taken
|
||||
boolean isFiat = CurrencyUtil.isFiatCurrency(currencyCode);
|
||||
boolean isStagenet = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_STAGENET;
|
||||
if (isFiat && isStagenet && HavenoUtils.centinerosToXmr(riskBasedTradeLimit) > OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value) {
|
||||
riskBasedTradeLimit = HavenoUtils.xmrToCentineros(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value);
|
||||
if (isFiat && isStagenet && riskBasedTradeLimit > OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact()) {
|
||||
riskBasedTradeLimit = OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact();
|
||||
}
|
||||
return Coin.valueOf(riskBasedTradeLimit);
|
||||
return BigInteger.valueOf(riskBasedTradeLimit);
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
|
@ -17,47 +17,39 @@
|
||||
|
||||
package bisq.core.payment.validation;
|
||||
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.validation.NumberValidator;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BtcValidator extends NumberValidator {
|
||||
|
||||
protected final CoinFormatter formatter;
|
||||
public class XmrValidator extends NumberValidator {
|
||||
|
||||
@Nullable
|
||||
@Setter
|
||||
protected Coin minValue;
|
||||
protected BigInteger minValue;
|
||||
|
||||
@Nullable
|
||||
@Setter
|
||||
protected Coin maxValue;
|
||||
protected BigInteger maxValue;
|
||||
|
||||
@Nullable
|
||||
@Setter
|
||||
@Getter
|
||||
protected Coin maxTradeLimit;
|
||||
protected BigInteger maxTradeLimit;
|
||||
|
||||
@Inject
|
||||
public BtcValidator(@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
|
||||
this.formatter = formatter;
|
||||
public XmrValidator() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ValidationResult validate(String input) {
|
||||
ValidationResult result = validateIfNotEmpty(input);
|
||||
@ -70,34 +62,20 @@ public class BtcValidator extends NumberValidator {
|
||||
result = result.andValidation(input,
|
||||
this::validateIfNotZero,
|
||||
this::validateIfNotNegative,
|
||||
this::validateIfNotFractionalBtcValue,
|
||||
this::validateIfNotFractionalXmrValue,
|
||||
this::validateIfNotExceedsMaxTradeLimit,
|
||||
this::validateIfNotExceedsMaxBtcValue,
|
||||
this::validateIfNotUnderMinValue,
|
||||
this::validateIfAboveDust);
|
||||
this::validateIfNotExceedsMaxValue,
|
||||
this::validateIfNotUnderMinValue);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected ValidationResult validateIfAboveDust(String input) {
|
||||
try {
|
||||
final Coin coin = Coin.parseCoin(input);
|
||||
if (Restrictions.isAboveDust(coin))
|
||||
return new ValidationResult(true);
|
||||
else
|
||||
return new ValidationResult(false, Res.get("validation.amountBelowDust",
|
||||
formatter.formatCoinWithCode(Restrictions.getMinNonDustOutput())));
|
||||
} catch (Throwable t) {
|
||||
return new ValidationResult(false, Res.get("validation.invalidInput", t.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
protected ValidationResult validateIfNotFractionalBtcValue(String input) {
|
||||
protected ValidationResult validateIfNotFractionalXmrValue(String input) {
|
||||
try {
|
||||
BigDecimal bd = new BigDecimal(input);
|
||||
final BigDecimal satoshis = bd.movePointRight(8);
|
||||
if (satoshis.scale() > 0)
|
||||
final BigDecimal atomicUnits = bd.movePointRight(HavenoUtils.XMR_SMALLEST_UNIT_EXPONENT);
|
||||
if (atomicUnits.scale() > 0)
|
||||
return new ValidationResult(false, Res.get("validation.btc.fraction"));
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
@ -106,11 +84,11 @@ public class BtcValidator extends NumberValidator {
|
||||
}
|
||||
}
|
||||
|
||||
protected ValidationResult validateIfNotExceedsMaxBtcValue(String input) {
|
||||
protected ValidationResult validateIfNotExceedsMaxValue(String input) {
|
||||
try {
|
||||
final Coin coin = Coin.parseCoin(input);
|
||||
if (maxValue != null && coin.compareTo(maxValue) > 0)
|
||||
return new ValidationResult(false, Res.get("validation.btc.toLarge", formatter.formatCoinWithCode(maxValue)));
|
||||
final BigInteger amount = HavenoUtils.parseXmr(input);
|
||||
if (maxValue != null && amount.compareTo(maxValue) > 0)
|
||||
return new ValidationResult(false, Res.get("validation.btc.toLarge", HavenoUtils.formatToXmrWithCode(maxValue)));
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
} catch (Throwable t) {
|
||||
@ -120,9 +98,9 @@ public class BtcValidator extends NumberValidator {
|
||||
|
||||
protected ValidationResult validateIfNotExceedsMaxTradeLimit(String input) {
|
||||
try {
|
||||
final Coin coin = Coin.parseCoin(input);
|
||||
if (maxTradeLimit != null && coin.compareTo(maxTradeLimit) > 0)
|
||||
return new ValidationResult(false, Res.get("validation.btc.exceedsMaxTradeLimit", formatter.formatCoinWithCode(maxTradeLimit)));
|
||||
final BigInteger amount = HavenoUtils.parseXmr(input);
|
||||
if (maxTradeLimit != null && amount.compareTo(maxTradeLimit) > 0)
|
||||
return new ValidationResult(false, Res.get("validation.btc.exceedsMaxTradeLimit", HavenoUtils.formatToXmrWithCode(maxTradeLimit)));
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
} catch (Throwable t) {
|
||||
@ -132,9 +110,9 @@ public class BtcValidator extends NumberValidator {
|
||||
|
||||
protected ValidationResult validateIfNotUnderMinValue(String input) {
|
||||
try {
|
||||
final Coin coin = Coin.parseCoin(input);
|
||||
if (minValue != null && coin.compareTo(minValue) < 0)
|
||||
return new ValidationResult(false, Res.get("validation.btc.toSmall", formatter.formatCoinWithCode(minValue)));
|
||||
final BigInteger amount = HavenoUtils.parseXmr(input);
|
||||
if (minValue != null && amount.compareTo(minValue) < 0)
|
||||
return new ValidationResult(false, Res.get("validation.btc.toSmall", HavenoUtils.formatToXmr(minValue)));
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
} catch (Throwable t) {
|
@ -56,7 +56,6 @@ import bisq.common.handlers.ResultHandler;
|
||||
import bisq.common.util.MathUtils;
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
@ -844,8 +843,8 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||
(contract.isBuyerMakerAndSellerTaker() ? contract.getMakerPayoutAddressString() : contract.getTakerPayoutAddressString()) :
|
||||
(contract.isBuyerMakerAndSellerTaker() ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString());
|
||||
String loserPayoutAddress = winnerPayoutAddress.equals(contract.getMakerPayoutAddressString()) ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString();
|
||||
BigInteger winnerPayoutAmount = HavenoUtils.coinToAtomicUnits(disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount());
|
||||
BigInteger loserPayoutAmount = HavenoUtils.coinToAtomicUnits(disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount());
|
||||
BigInteger winnerPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount();
|
||||
BigInteger loserPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount();
|
||||
|
||||
// check sufficient balance
|
||||
if (winnerPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Winner payout cannot be negative");
|
||||
@ -1039,26 +1038,26 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||
}
|
||||
|
||||
// The amount we would get if we do a new trade with current price
|
||||
Coin potentialAmountAtDisputeOpening = priceAtDisputeOpening.getAmountByVolume(contract.getTradeVolume());
|
||||
Coin buyerSecurityDeposit = Coin.valueOf(offerPayload.getBuyerSecurityDeposit());
|
||||
Coin minRefundAtMediatedDispute = Restrictions.getMinRefundAtMediatedDispute();
|
||||
BigInteger potentialAmountAtDisputeOpening = priceAtDisputeOpening.getAmountByVolume(contract.getTradeVolume());
|
||||
BigInteger buyerSecurityDeposit = BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit());
|
||||
BigInteger minRefundAtMediatedDispute = Restrictions.getMinRefundAtMediatedDispute();
|
||||
// minRefundAtMediatedDispute is always larger as buyerSecurityDeposit at mediated payout, we ignore refund agent case here as there it can be 0.
|
||||
Coin maxLossSecDeposit = buyerSecurityDeposit.subtract(minRefundAtMediatedDispute);
|
||||
Coin tradeAmount = contract.getTradeAmount();
|
||||
Coin potentialGain = potentialAmountAtDisputeOpening.subtract(tradeAmount).subtract(maxLossSecDeposit);
|
||||
BigInteger maxLossSecDeposit = buyerSecurityDeposit.subtract(minRefundAtMediatedDispute);
|
||||
BigInteger tradeAmount = contract.getTradeAmount();
|
||||
BigInteger potentialGain = potentialAmountAtDisputeOpening.subtract(tradeAmount).subtract(maxLossSecDeposit);
|
||||
String optionTradeDetails;
|
||||
// We don't translate those strings (yet) as it is only displayed to mediators/arbitrators.
|
||||
String headline;
|
||||
if (potentialGain.isPositive()) {
|
||||
if (potentialGain.compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
headline = "This might be a potential option trade!";
|
||||
optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + potentialAmountAtDisputeOpening.toFriendlyString() +
|
||||
"\nMax loss of security deposit is: " + maxLossSecDeposit.toFriendlyString() +
|
||||
"\nPossible gain from an option trade is: " + potentialGain.toFriendlyString();
|
||||
optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + HavenoUtils.formatToXmrWithCode(potentialAmountAtDisputeOpening) +
|
||||
"\nMax loss of security deposit is: " + HavenoUtils.formatToXmrWithCode(maxLossSecDeposit) +
|
||||
"\nPossible gain from an option trade is: " + HavenoUtils.formatToXmrWithCode(potentialGain);
|
||||
} else {
|
||||
headline = "It does not appear to be an option trade.";
|
||||
optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + potentialAmountAtDisputeOpening.toFriendlyString() +
|
||||
"\nMax loss of security deposit is: " + maxLossSecDeposit.toFriendlyString() +
|
||||
"\nPossible loss from an option trade is: " + potentialGain.multiply(-1).toFriendlyString();
|
||||
optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + HavenoUtils.formatToXmrWithCode(potentialAmountAtDisputeOpening) +
|
||||
"\nMax loss of security deposit is: " + HavenoUtils.formatToXmrWithCode(maxLossSecDeposit) +
|
||||
"\nPossible loss from an option trade is: " + HavenoUtils.formatToXmrWithCode(potentialGain.multiply(BigInteger.valueOf(-1)));
|
||||
}
|
||||
|
||||
String percentagePriceDetails = offerPayload.isUseMarketBasedPrice() ?
|
||||
@ -1067,7 +1066,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||
|
||||
String priceInfoText = "System message: " + headline +
|
||||
"\n\nTrade price: " + contract.getPrice().toFriendlyString() + percentagePriceDetails +
|
||||
"\nTrade amount: " + tradeAmount.toFriendlyString() +
|
||||
"\nTrade amount: " + HavenoUtils.formatToXmrWithCode(tradeAmount) +
|
||||
"\nPrice at dispute opening: " + priceAtDisputeOpening.toFriendlyString() +
|
||||
optionTradeDetails;
|
||||
|
||||
|
@ -23,8 +23,6 @@ import bisq.common.proto.ProtoUtil;
|
||||
import bisq.common.proto.network.NetworkPayload;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
@ -32,6 +30,7 @@ import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -206,20 +205,20 @@ public final class DisputeResult implements NetworkPayload {
|
||||
return summaryNotesProperty;
|
||||
}
|
||||
|
||||
public void setBuyerPayoutAmount(Coin buyerPayoutAmount) {
|
||||
this.buyerPayoutAmount = buyerPayoutAmount.value;
|
||||
public void setBuyerPayoutAmount(BigInteger buyerPayoutAmount) {
|
||||
this.buyerPayoutAmount = buyerPayoutAmount.longValueExact();
|
||||
}
|
||||
|
||||
public Coin getBuyerPayoutAmount() {
|
||||
return Coin.valueOf(buyerPayoutAmount);
|
||||
public BigInteger getBuyerPayoutAmount() {
|
||||
return BigInteger.valueOf(buyerPayoutAmount);
|
||||
}
|
||||
|
||||
public void setSellerPayoutAmount(Coin sellerPayoutAmount) {
|
||||
this.sellerPayoutAmount = sellerPayoutAmount.value;
|
||||
public void setSellerPayoutAmount(BigInteger sellerPayoutAmount) {
|
||||
this.sellerPayoutAmount = sellerPayoutAmount.longValueExact();
|
||||
}
|
||||
|
||||
public Coin getSellerPayoutAmount() {
|
||||
return Coin.valueOf(sellerPayoutAmount);
|
||||
public BigInteger getSellerPayoutAmount() {
|
||||
return BigInteger.valueOf(sellerPayoutAmount);
|
||||
}
|
||||
|
||||
public void setCloseDate(Date closeDate) {
|
||||
|
@ -386,13 +386,13 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
||||
|
||||
// verify payouts sum to unlocked balance within loss of precision due to conversion to centineros
|
||||
BigInteger txCost = arbitratorSignedPayoutTx.getFee().add(arbitratorSignedPayoutTx.getChangeAmount()); // fee + lost dust change
|
||||
if (trade.getWallet().getUnlockedBalance().subtract(actualWinnerAmount.add(actualLoserAmount).add(txCost)).compareTo(HavenoUtils.CENTINEROS_AU_MULTIPLIER) > 0) {
|
||||
if (trade.getWallet().getUnlockedBalance().subtract(actualWinnerAmount.add(actualLoserAmount).add(txCost)).compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
throw new RuntimeException("The dispute payout amounts do not sum to the wallet's unlocked balance while verifying the dispute payout tx, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs sum payout amount=" + actualWinnerAmount.add(actualLoserAmount) + ", winner payout=" + actualWinnerAmount + ", loser payout=" + actualLoserAmount);
|
||||
}
|
||||
|
||||
// get expected payout amounts
|
||||
BigInteger expectedWinnerAmount = HavenoUtils.coinToAtomicUnits(disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount());
|
||||
BigInteger expectedLoserAmount = HavenoUtils.coinToAtomicUnits(disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount());
|
||||
BigInteger expectedWinnerAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount();
|
||||
BigInteger expectedLoserAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount();
|
||||
|
||||
// add any loss of precision to winner amount
|
||||
expectedWinnerAmount = expectedWinnerAmount.add(trade.getWallet().getUnlockedBalance().subtract(expectedWinnerAmount.add(expectedLoserAmount)));
|
||||
|
@ -20,8 +20,7 @@ package bisq.core.support.dispute.arbitration;
|
||||
import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -34,12 +33,12 @@ public class TraderDataItem {
|
||||
private final PaymentAccountPayload paymentAccountPayload;
|
||||
@EqualsAndHashCode.Include
|
||||
private final AccountAgeWitness accountAgeWitness;
|
||||
private final Coin tradeAmount;
|
||||
private final BigInteger tradeAmount;
|
||||
private final PublicKey peersPubKey;
|
||||
|
||||
public TraderDataItem(PaymentAccountPayload paymentAccountPayload,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
Coin tradeAmount,
|
||||
BigInteger tradeAmount,
|
||||
PublicKey peersPubKey) {
|
||||
this.paymentAccountPayload = paymentAccountPayload;
|
||||
this.accountAgeWitness = accountAgeWitness;
|
||||
|
@ -51,11 +51,10 @@ import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -194,8 +193,8 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
|
||||
Trade trade = tradeOptional.get();
|
||||
if (trade.getDisputeState() == Trade.DisputeState.MEDIATION_REQUESTED ||
|
||||
trade.getDisputeState() == Trade.DisputeState.MEDIATION_STARTED_BY_PEER) {
|
||||
trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmount().value);
|
||||
trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmount().value);
|
||||
trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmount().longValueExact());
|
||||
trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmount().longValueExact());
|
||||
|
||||
trade.setDisputeState(Trade.DisputeState.MEDIATION_CLOSED);
|
||||
|
||||
@ -228,11 +227,11 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
|
||||
Optional<Dispute> optionalDispute = findDispute(tradeId);
|
||||
checkArgument(optionalDispute.isPresent(), "dispute must be present");
|
||||
DisputeResult disputeResult = optionalDispute.get().getDisputeResultProperty().get();
|
||||
Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
ProcessModel processModel = trade.getProcessModel();
|
||||
processModel.setBuyerPayoutAmountFromMediation(buyerPayoutAmount.value);
|
||||
processModel.setSellerPayoutAmountFromMediation(sellerPayoutAmount.value);
|
||||
processModel.setBuyerPayoutAmountFromMediation(buyerPayoutAmount.longValueExact());
|
||||
processModel.setSellerPayoutAmountFromMediation(sellerPayoutAmount.longValueExact());
|
||||
DisputeProtocol tradeProtocol = (DisputeProtocol) tradeManager.getTradeProtocol(trade);
|
||||
|
||||
trade.setMediationResultState(MediationResultState.MEDIATION_RESULT_ACCEPTED);
|
||||
|
@ -9,8 +9,7 @@ import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -22,8 +21,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class ArbitratorTrade extends Trade {
|
||||
|
||||
public ArbitratorTrade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takerFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -35,7 +34,7 @@ public class ArbitratorTrade extends Trade {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getPayoutAmount() {
|
||||
public BigInteger getPayoutAmount() {
|
||||
throw new RuntimeException("Arbitrator does not have a payout amount");
|
||||
}
|
||||
|
||||
@ -62,8 +61,8 @@ public class ArbitratorTrade extends Trade {
|
||||
}
|
||||
return fromProto(new ArbitratorTrade(
|
||||
Offer.fromProto(proto.getOffer()),
|
||||
Coin.valueOf(proto.getAmountAsLong()),
|
||||
Coin.valueOf(proto.getTakerFeeAsLong()),
|
||||
BigInteger.valueOf(proto.getAmountAsLong()),
|
||||
BigInteger.valueOf(proto.getTakerFeeAsLong()),
|
||||
proto.getPrice(),
|
||||
xmrWalletService,
|
||||
processModel,
|
||||
|
@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -40,8 +39,8 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public BuyerAsMakerTrade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takeOfferFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takeOfferFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -84,8 +83,8 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
|
||||
}
|
||||
BuyerAsMakerTrade trade = new BuyerAsMakerTrade(
|
||||
Offer.fromProto(proto.getOffer()),
|
||||
Coin.valueOf(proto.getAmountAsLong()),
|
||||
Coin.valueOf(proto.getTakerFeeAsLong()),
|
||||
BigInteger.valueOf(proto.getAmountAsLong()),
|
||||
BigInteger.valueOf(proto.getTakerFeeAsLong()),
|
||||
proto.getPrice(),
|
||||
xmrWalletService,
|
||||
processModel,
|
||||
|
@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -42,8 +41,8 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public BuyerAsTakerTrade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takerFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -87,8 +86,8 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
|
||||
}
|
||||
return fromProto(new BuyerAsTakerTrade(
|
||||
Offer.fromProto(proto.getOffer()),
|
||||
Coin.valueOf(proto.getAmountAsLong()),
|
||||
Coin.valueOf(proto.getTakerFeeAsLong()),
|
||||
BigInteger.valueOf(proto.getAmountAsLong()),
|
||||
BigInteger.valueOf(proto.getTakerFeeAsLong()),
|
||||
proto.getPrice(),
|
||||
xmrWalletService,
|
||||
processModel,
|
||||
|
@ -23,19 +23,19 @@ import bisq.core.trade.protocol.ProcessModel;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Slf4j
|
||||
public abstract class BuyerTrade extends Trade {
|
||||
BuyerTrade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takerFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -56,7 +56,7 @@ public abstract class BuyerTrade extends Trade {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getPayoutAmount() {
|
||||
public BigInteger getPayoutAmount() {
|
||||
checkNotNull(getAmount(), "Invalid state: getTradeAmount() = null");
|
||||
return checkNotNull(getOffer()).getBuyerSecurityDeposit().add(getAmount());
|
||||
}
|
||||
|
@ -48,8 +48,6 @@ import static bisq.core.util.FormattingUtils.formatPercentagePrice;
|
||||
import static bisq.core.util.FormattingUtils.formatToPercentWithSymbol;
|
||||
import static bisq.core.util.VolumeUtil.formatVolume;
|
||||
import static bisq.core.util.VolumeUtil.formatVolumeWithCode;
|
||||
import static org.bitcoinj.core.TransactionConfidence.ConfidenceType.BUILDING;
|
||||
import static org.bitcoinj.core.TransactionConfidence.ConfidenceType.PENDING;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
@ -59,7 +57,6 @@ public class ClosedTradableFormatter {
|
||||
private static final String I18N_KEY_TOTAL_AMOUNT = "closedTradesSummaryWindow.totalAmount.value";
|
||||
private static final String I18N_KEY_TOTAL_TX_FEE = "closedTradesSummaryWindow.totalMinerFee.value";
|
||||
private static final String I18N_KEY_TOTAL_TRADE_FEE_BTC = "closedTradesSummaryWindow.totalTradeFeeInBtc.value";
|
||||
private static final String I18N_KEY_TOTAL_TRADE_FEE_BSQ = "closedTradesSummaryWindow.totalTradeFeeInBsq.value";
|
||||
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final ClosedTradableManager closedTradableManager;
|
||||
@ -72,7 +69,7 @@ public class ClosedTradableFormatter {
|
||||
}
|
||||
|
||||
public String getAmountAsString(Tradable tradable) {
|
||||
return tradable.getOptionalAmount().map(btcFormatter::formatCoin).orElse("");
|
||||
return tradable.getOptionalAmount().map(HavenoUtils::formatToXmr).orElse("");
|
||||
}
|
||||
|
||||
public String getTotalAmountWithVolumeAsString(Coin totalTradeAmount, Volume volume) {
|
||||
@ -93,11 +90,11 @@ public class ClosedTradableFormatter {
|
||||
}
|
||||
|
||||
public String getBuyerSecurityDepositAsString(Tradable tradable) {
|
||||
return btcFormatter.formatCoin(tradable.getOffer().getBuyerSecurityDeposit());
|
||||
return HavenoUtils.formatToXmr(tradable.getOffer().getBuyerSecurityDeposit());
|
||||
}
|
||||
|
||||
public String getSellerSecurityDepositAsString(Tradable tradable) {
|
||||
return btcFormatter.formatCoin(tradable.getOffer().getSellerSecurityDeposit());
|
||||
return HavenoUtils.formatToXmr(tradable.getOffer().getSellerSecurityDeposit());
|
||||
}
|
||||
|
||||
public String getTradeFeeAsString(Tradable tradable, boolean appendCode) {
|
||||
|
@ -41,6 +41,7 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.Instant;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -229,8 +230,8 @@ public class ClosedTradableManager implements PersistedDataHost {
|
||||
|
||||
public long getBtcTradeFee(Tradable tradable) {
|
||||
return isMaker(tradable) ?
|
||||
tradable.getOptionalMakerFee().orElse(Coin.ZERO).value :
|
||||
tradable.getOptionalTakerFee().orElse(Coin.ZERO).value;
|
||||
tradable.getOptionalMakerFee().orElse(BigInteger.valueOf(0)).longValueExact() :
|
||||
tradable.getOptionalTakerFee().orElse(BigInteger.valueOf(0)).longValueExact();
|
||||
}
|
||||
|
||||
public boolean isMaker(Tradable tradable) {
|
||||
|
@ -33,8 +33,6 @@ import bisq.common.proto.network.NetworkPayload;
|
||||
import bisq.common.util.JsonExclude;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.Value;
|
||||
@ -44,6 +42,8 @@ import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Slf4j
|
||||
@Value
|
||||
public final class Contract implements NetworkPayload {
|
||||
@ -209,8 +209,8 @@ public final class Contract implements NetworkPayload {
|
||||
return makerPaymentMethodId;
|
||||
}
|
||||
|
||||
public Coin getTradeAmount() {
|
||||
return Coin.valueOf(tradeAmount);
|
||||
public BigInteger getTradeAmount() {
|
||||
return BigInteger.valueOf(tradeAmount);
|
||||
}
|
||||
|
||||
public Volume getTradeVolume() {
|
||||
|
@ -25,8 +25,6 @@ import bisq.core.trade.messages.InitTradeRequest;
|
||||
import bisq.core.trade.messages.PaymentReceivedMessage;
|
||||
import bisq.core.trade.messages.PaymentSentMessage;
|
||||
import bisq.core.util.JsonUtil;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
import bisq.core.util.coin.CoinUtil;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
@ -36,7 +34,6 @@ import bisq.common.crypto.Sig;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Charsets;
|
||||
@ -68,9 +65,10 @@ import javax.annotation.Nullable;
|
||||
@Slf4j
|
||||
public class HavenoUtils {
|
||||
|
||||
public static int XMR_SMALLEST_UNIT_EXPONENT = 12;
|
||||
public static final String LOOPBACK_HOST = "127.0.0.1"; // local loopback address to host Monero node
|
||||
public static final String LOCALHOST = "localhost";
|
||||
public static final BigInteger CENTINEROS_AU_MULTIPLIER = new BigInteger("10000");
|
||||
private static final long CENTINEROS_AU_MULTIPLIER = 10000;
|
||||
private static final BigInteger XMR_AU_MULTIPLIER = new BigInteger("1000000000000");
|
||||
public static final DecimalFormat XMR_FORMATTER = new DecimalFormat("0.000000000000");
|
||||
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
@ -79,12 +77,15 @@ public class HavenoUtils {
|
||||
|
||||
public static ArbitrationManager arbitrationManager; // TODO: better way to share reference?
|
||||
|
||||
|
||||
// ----------------------- CONVERSION UTILS -------------------------------
|
||||
|
||||
public static BigInteger coinToAtomicUnits(Coin coin) {
|
||||
return centinerosToAtomicUnits(coin.value);
|
||||
}
|
||||
|
||||
public static BigInteger centinerosToAtomicUnits(long centineros) {
|
||||
return BigInteger.valueOf(centineros).multiply(CENTINEROS_AU_MULTIPLIER);
|
||||
return BigInteger.valueOf(centineros).multiply(BigInteger.valueOf(CENTINEROS_AU_MULTIPLIER));
|
||||
}
|
||||
|
||||
public static double centinerosToXmr(long centineros) {
|
||||
@ -95,12 +96,12 @@ public class HavenoUtils {
|
||||
return atomicUnitsToCoin(centinerosToAtomicUnits(centineros));
|
||||
}
|
||||
|
||||
public static long atomicUnitsToCentineros(long atomicUnits) { // TODO: atomic units should be BigInteger; remove this?
|
||||
return atomicUnits / CENTINEROS_AU_MULTIPLIER.longValue();
|
||||
public static long atomicUnitsToCentineros(long atomicUnits) {
|
||||
return atomicUnits / CENTINEROS_AU_MULTIPLIER;
|
||||
}
|
||||
|
||||
public static long atomicUnitsToCentineros(BigInteger atomicUnits) {
|
||||
return atomicUnits.divide(CENTINEROS_AU_MULTIPLIER).longValueExact();
|
||||
return atomicUnits.divide(BigInteger.valueOf(CENTINEROS_AU_MULTIPLIER)).longValueExact();
|
||||
}
|
||||
|
||||
public static Coin atomicUnitsToCoin(long atomicUnits) {
|
||||
@ -131,11 +132,19 @@ public class HavenoUtils {
|
||||
return atomicUnitsToXmr(coinToAtomicUnits(coin));
|
||||
}
|
||||
|
||||
public static String formatXmrWithCode(Coin coin) {
|
||||
return formatXmrWithCode(coinToAtomicUnits(coin).longValueExact());
|
||||
|
||||
// ------------------------- FORMAT UTILS ---------------------------------
|
||||
|
||||
public static String formatToXmr(BigInteger atomicUnits) {
|
||||
if (atomicUnits == null) return "";
|
||||
return formatToXmr(atomicUnits.longValueExact());
|
||||
}
|
||||
|
||||
public static String formatXmrWithCode(long atomicUnits) {
|
||||
public static String formatToXmr(BigInteger atomicUnits, int decimalPlaces) {
|
||||
return applyDecimals(formatToXmr(atomicUnits), decimalPlaces);
|
||||
}
|
||||
|
||||
public static String formatToXmr(long atomicUnits) {
|
||||
String formatted = XMR_FORMATTER.format(atomicUnitsToXmr(atomicUnits));
|
||||
|
||||
// strip trailing 0s
|
||||
@ -144,55 +153,87 @@ public class HavenoUtils {
|
||||
formatted = formatted.substring(0, formatted.length() - 1);
|
||||
}
|
||||
}
|
||||
return formatted.concat(" ").concat("XMR");
|
||||
return applyDecimals(formatted, 2);
|
||||
}
|
||||
|
||||
private static final MonetaryFormat xmrCoinFormat = Config.baseCurrencyNetworkParameters().getMonetaryFormat();
|
||||
private static String applyDecimals(String decimalStr, int decimalPlaces) {
|
||||
if (decimalStr.contains(".")) return decimalStr + getNumZeros(decimalPlaces - (decimalStr.length() - decimalStr.indexOf(".") - 1));
|
||||
else return decimalStr + "." + getNumZeros(decimalPlaces);
|
||||
}
|
||||
|
||||
private static String getNumZeros(int numZeros) {
|
||||
String zeros = "";
|
||||
for (int i = 0; i < numZeros; i++) zeros += "0";
|
||||
return zeros;
|
||||
}
|
||||
|
||||
public static String formatToXmrWithCode(BigInteger atomicUnits) {
|
||||
if (atomicUnits == null) return "";
|
||||
return formatToXmrWithCode(atomicUnits.longValueExact());
|
||||
}
|
||||
|
||||
public static String formatToXmrWithCode(long atomicUnits) {
|
||||
return formatToXmr(atomicUnits).concat(" XMR");
|
||||
}
|
||||
|
||||
public static BigInteger parseXmr(String input) {
|
||||
if (input == null || input.length() == 0) return BigInteger.valueOf(0);
|
||||
try {
|
||||
return xmrToAtomicUnits(new BigDecimal(input).doubleValue());
|
||||
} catch (Exception e) {
|
||||
log.warn("Exception at parseXmr: " + e.toString());
|
||||
return BigInteger.valueOf(0);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------ FEE UTILS -------------------------------
|
||||
|
||||
@Nullable
|
||||
public static Coin getMakerFee(@Nullable Coin amount) {
|
||||
public static BigInteger getMakerFee(@Nullable BigInteger amount) {
|
||||
if (amount != null) {
|
||||
Coin feePerXmr = getFeePerXmr(HavenoUtils.getMakerFeePerXmr(), amount);
|
||||
return CoinUtil.maxCoin(feePerXmr, HavenoUtils.getMinMakerFee());
|
||||
BigInteger feePerXmr = getFeePerXmr(HavenoUtils.getMakerFeePerXmr(), amount);
|
||||
return feePerXmr.max(HavenoUtils.getMinMakerFee());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Coin getTakerFee(@Nullable Coin amount) {
|
||||
public static BigInteger getTakerFee(@Nullable BigInteger amount) {
|
||||
if (amount != null) {
|
||||
Coin feePerXmr = HavenoUtils.getFeePerXmr(HavenoUtils.getTakerFeePerXmr(), amount);
|
||||
return CoinUtil.maxCoin(feePerXmr, HavenoUtils.getMinTakerFee());
|
||||
BigInteger feePerXmr = HavenoUtils.getFeePerXmr(HavenoUtils.getTakerFeePerXmr(), amount);
|
||||
return feePerXmr.max(HavenoUtils.getMinTakerFee());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Coin getMakerFeePerXmr() {
|
||||
return ParsingUtils.parseToCoin("0.001", xmrCoinFormat);
|
||||
private static BigInteger getMakerFeePerXmr() {
|
||||
return HavenoUtils.xmrToAtomicUnits(0.001);
|
||||
}
|
||||
|
||||
public static Coin getMinMakerFee() {
|
||||
return ParsingUtils.parseToCoin("0.00005", xmrCoinFormat);
|
||||
public static BigInteger getMinMakerFee() {
|
||||
return HavenoUtils.xmrToAtomicUnits(0.00005);
|
||||
}
|
||||
|
||||
private static Coin getTakerFeePerXmr() {
|
||||
return ParsingUtils.parseToCoin("0.003", xmrCoinFormat);
|
||||
private static BigInteger getTakerFeePerXmr() {
|
||||
return HavenoUtils.xmrToAtomicUnits(0.003);
|
||||
}
|
||||
|
||||
public static Coin getMinTakerFee() {
|
||||
return ParsingUtils.parseToCoin("0.00005", xmrCoinFormat);
|
||||
public static BigInteger getMinTakerFee() {
|
||||
return HavenoUtils.xmrToAtomicUnits(0.00005);
|
||||
}
|
||||
|
||||
public static Coin getFeePerXmr(Coin feePerXmr, Coin amount) {
|
||||
double feePerBtcAsDouble = feePerXmr != null ? (double) feePerXmr.value : 0;
|
||||
double amountAsDouble = amount != null ? (double) amount.value : 0;
|
||||
double btcAsDouble = (double) Coin.COIN.value;
|
||||
double fact = amountAsDouble / btcAsDouble;
|
||||
return Coin.valueOf(Math.round(feePerBtcAsDouble * fact));
|
||||
public static BigInteger getFeePerXmr(BigInteger feePerXmr, BigInteger amount) {
|
||||
BigDecimal feePerXmrAsDecimal = feePerXmr == null ? BigDecimal.valueOf(0) : new BigDecimal(feePerXmr);
|
||||
BigDecimal amountAsDecimal = amount == null ? BigDecimal.valueOf(0) : new BigDecimal(amount);
|
||||
BigDecimal xmrAsDecimal = new BigDecimal(HavenoUtils.xmrToAtomicUnits(1.0));
|
||||
return feePerXmrAsDecimal.multiply(amountAsDecimal.divide(xmrAsDecimal)).toBigInteger();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------- OTHER UTILS ------------------------------
|
||||
|
||||
/**
|
||||
* Get address to collect trade fees.
|
||||
*
|
||||
|
@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -42,8 +41,8 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public SellerAsMakerTrade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takerFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -87,8 +86,8 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
|
||||
}
|
||||
SellerAsMakerTrade trade = new SellerAsMakerTrade(
|
||||
Offer.fromProto(proto.getOffer()),
|
||||
Coin.valueOf(proto.getAmountAsLong()),
|
||||
Coin.valueOf(proto.getTakerFeeAsLong()),
|
||||
BigInteger.valueOf(proto.getAmountAsLong()),
|
||||
BigInteger.valueOf(proto.getTakerFeeAsLong()),
|
||||
proto.getPrice(),
|
||||
xmrWalletService,
|
||||
processModel,
|
||||
|
@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -42,8 +41,8 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public SellerAsTakerTrade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takerFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -87,8 +86,8 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
|
||||
}
|
||||
return fromProto(new SellerAsTakerTrade(
|
||||
Offer.fromProto(proto.getOffer()),
|
||||
Coin.valueOf(proto.getAmountAsLong()),
|
||||
Coin.valueOf(proto.getTakerFeeAsLong()),
|
||||
BigInteger.valueOf(proto.getAmountAsLong()),
|
||||
BigInteger.valueOf(proto.getTakerFeeAsLong()),
|
||||
proto.getPrice(),
|
||||
xmrWalletService,
|
||||
processModel,
|
||||
|
@ -18,25 +18,24 @@
|
||||
package bisq.core.trade;
|
||||
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.trade.protocol.ProcessModel;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Slf4j
|
||||
public abstract class SellerTrade extends Trade {
|
||||
SellerTrade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takerFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -57,7 +56,7 @@ public abstract class SellerTrade extends Trade {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getPayoutAmount() {
|
||||
public BigInteger getPayoutAmount() {
|
||||
return checkNotNull(getOffer()).getSellerSecurityDeposit();
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ import bisq.common.proto.persistable.PersistablePayload;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -54,7 +55,7 @@ public interface Tradable extends PersistablePayload {
|
||||
return asTradeModel().map(Trade::getPrice).or(() -> Optional.ofNullable(getOffer().getPrice()));
|
||||
}
|
||||
|
||||
default Optional<Coin> getOptionalAmount() {
|
||||
default Optional<BigInteger> getOptionalAmount() {
|
||||
return asTradeModel().map(Trade::getAmount);
|
||||
}
|
||||
|
||||
@ -66,11 +67,11 @@ public interface Tradable extends PersistablePayload {
|
||||
return asTradeModel().map(Trade::getTxFee);
|
||||
}
|
||||
|
||||
default Optional<Coin> getOptionalTakerFee() {
|
||||
default Optional<BigInteger> getOptionalTakerFee() {
|
||||
return asTradeModel().map(Trade::getTakerFee);
|
||||
}
|
||||
|
||||
default Optional<Coin> getOptionalMakerFee() {
|
||||
default Optional<BigInteger> getOptionalMakerFee() {
|
||||
return asTradeModel().map(Trade::getOffer).map(Offer::getMakerFee).or(() -> Optional.ofNullable(getOffer().getMakerFee()));
|
||||
}
|
||||
|
||||
|
@ -375,7 +375,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
@Getter
|
||||
transient final private Coin txFee;
|
||||
@Getter
|
||||
transient final private Coin takerFee;
|
||||
transient final private BigInteger takerFee;
|
||||
@Getter
|
||||
transient final private XmrWalletService xmrWalletService;
|
||||
|
||||
@ -402,9 +402,9 @@ public abstract class Trade implements Tradable, Model {
|
||||
|
||||
// Added in v1.2.0
|
||||
@Nullable
|
||||
transient private Coin tradeAmount;
|
||||
transient private BigInteger tradeAmount;
|
||||
|
||||
transient private ObjectProperty<Coin> tradeAmountProperty;
|
||||
transient private ObjectProperty<BigInteger> tradeAmountProperty;
|
||||
transient private ObjectProperty<Volume> tradeVolumeProperty;
|
||||
|
||||
// Added in v1.1.6
|
||||
@ -469,8 +469,8 @@ public abstract class Trade implements Tradable, Model {
|
||||
|
||||
// maker
|
||||
protected Trade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin takerFee, // TODO (woodser): makerFee, takerFee, but not given one during construction
|
||||
BigInteger tradeAmount,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
XmrWalletService xmrWalletService,
|
||||
ProcessModel processModel,
|
||||
@ -487,7 +487,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
this.processModel = processModel;
|
||||
this.uid = uid;
|
||||
|
||||
this.takerFeeAsLong = takerFee.value;
|
||||
this.takerFeeAsLong = takerFee.longValueExact();
|
||||
this.takeOfferDate = new Date().getTime();
|
||||
this.tradeListeners = new ArrayList<TradeListener>();
|
||||
|
||||
@ -503,9 +503,9 @@ public abstract class Trade implements Tradable, Model {
|
||||
// taker
|
||||
@SuppressWarnings("NullableProblems")
|
||||
protected Trade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
Coin txFee,
|
||||
Coin takerFee,
|
||||
BigInteger tradeAmount,
|
||||
BigInteger txFee,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
@Nullable NodeAddress mediatorNodeAddress, // TODO (woodser): remove mediator, refund agent from trade
|
||||
@Nullable NodeAddress refundAgentNodeAddress,
|
||||
@ -532,9 +532,9 @@ public abstract class Trade implements Tradable, Model {
|
||||
// arbitrator
|
||||
@SuppressWarnings("NullableProblems")
|
||||
protected Trade(Offer offer,
|
||||
Coin tradeAmount,
|
||||
BigInteger tradeAmount,
|
||||
Coin txFee,
|
||||
Coin takerFee,
|
||||
BigInteger takerFee,
|
||||
long tradePrice,
|
||||
NodeAddress makerNodeAddress,
|
||||
NodeAddress takerNodeAddress,
|
||||
@ -860,7 +860,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
boolean isBuyerMakerAndSellerTaker = getOffer().getDirection() == OfferDirection.BUY;
|
||||
Contract contract = new Contract(
|
||||
getOffer().getOfferPayload(),
|
||||
checkNotNull(getAmount()).value,
|
||||
checkNotNull(getAmount()).longValueExact(),
|
||||
getPrice().getValue(),
|
||||
(isBuyerMakerAndSellerTaker ? getMaker() : getTaker()).getNodeAddress(), // buyer node address // TODO (woodser): use maker and taker node address instead of buyer and seller node address for consistency
|
||||
(isBuyerMakerAndSellerTaker ? getTaker() : getMaker()).getNodeAddress(), // seller node address
|
||||
@ -905,7 +905,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
Preconditions.checkNotNull(buyerPayoutAddress, "Buyer payout address must not be null");
|
||||
BigInteger sellerDepositAmount = multisigWallet.getTx(this.getSeller().getDepositTxHash()).getIncomingAmount();
|
||||
BigInteger buyerDepositAmount = multisigWallet.getTx(this.getBuyer().getDepositTxHash()).getIncomingAmount();
|
||||
BigInteger tradeAmount = HavenoUtils.coinToAtomicUnits(this.getAmount());
|
||||
BigInteger tradeAmount = getAmount();
|
||||
BigInteger buyerPayoutAmount = buyerDepositAmount.add(tradeAmount);
|
||||
BigInteger sellerPayoutAmount = sellerDepositAmount.subtract(tradeAmount);
|
||||
|
||||
@ -956,7 +956,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
Contract contract = getContract();
|
||||
BigInteger sellerDepositAmount = wallet.getTx(getSeller().getDepositTxHash()).getIncomingAmount(); // TODO (woodser): redundancy of processModel.getPreparedDepositTxId() vs this.getDepositTxId() necessary or avoidable?
|
||||
BigInteger buyerDepositAmount = wallet.getTx(getBuyer().getDepositTxHash()).getIncomingAmount();
|
||||
BigInteger tradeAmount = HavenoUtils.coinToAtomicUnits(getAmount());
|
||||
BigInteger tradeAmount = getAmount();
|
||||
|
||||
// describe payout tx
|
||||
MoneroTxSet describedTxSet = wallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(payoutTxHex));
|
||||
@ -1111,7 +1111,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
// by mediators and we keep the confirm disabled to avoid that the seller can complete the trade
|
||||
// without the penalty.
|
||||
long payoutAmountFromMediation = processModel.getSellerPayoutAmountFromMediation();
|
||||
long normalPayoutAmount = getSellerSecurityDeposit().value;
|
||||
long normalPayoutAmount = getSellerSecurityDeposit().longValueExact();
|
||||
return payoutAmountFromMediation < normalPayoutAmount;
|
||||
}
|
||||
|
||||
@ -1157,7 +1157,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
// Abstract
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public abstract Coin getPayoutAmount();
|
||||
public abstract BigInteger getPayoutAmount();
|
||||
|
||||
public abstract boolean confirmPermitted();
|
||||
|
||||
@ -1263,9 +1263,9 @@ public abstract class Trade implements Tradable, Model {
|
||||
tradePeriodStateProperty.set(tradePeriodState);
|
||||
}
|
||||
|
||||
public void setAmount(Coin tradeAmount) {
|
||||
public void setAmount(BigInteger tradeAmount) {
|
||||
this.tradeAmount = tradeAmount;
|
||||
amountAsLong = tradeAmount.value;
|
||||
amountAsLong = tradeAmount.longValueExact();
|
||||
getAmountProperty().set(tradeAmount);
|
||||
getVolumeProperty().set(getVolume());
|
||||
}
|
||||
@ -1535,7 +1535,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
return tradePeriodStateProperty;
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
|
||||
public ReadOnlyObjectProperty<BigInteger> tradeAmountProperty() {
|
||||
return tradeAmountProperty;
|
||||
}
|
||||
|
||||
@ -1567,24 +1567,24 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Coin getAmount() {
|
||||
public BigInteger getAmount() {
|
||||
if (tradeAmount == null)
|
||||
tradeAmount = Coin.valueOf(amountAsLong);
|
||||
tradeAmount = BigInteger.valueOf(amountAsLong);
|
||||
return tradeAmount;
|
||||
}
|
||||
|
||||
public Coin getMakerFee() {
|
||||
public BigInteger getMakerFee() {
|
||||
return offer.getMakerFee();
|
||||
}
|
||||
|
||||
public Coin getBuyerSecurityDeposit() {
|
||||
public BigInteger getBuyerSecurityDeposit() {
|
||||
if (getBuyer().getDepositTxHash() == null) return null;
|
||||
return HavenoUtils.centinerosToCoin(getBuyer().getSecurityDeposit());
|
||||
return BigInteger.valueOf(getBuyer().getSecurityDeposit());
|
||||
}
|
||||
|
||||
public Coin getSellerSecurityDeposit() {
|
||||
public BigInteger getSellerSecurityDeposit() {
|
||||
if (getSeller().getDepositTxHash() == null) return null;
|
||||
return HavenoUtils.centinerosToCoin(getSeller().getSecurityDeposit());
|
||||
return BigInteger.valueOf(getSeller().getSecurityDeposit());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -1627,7 +1627,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// lazy initialization
|
||||
private ObjectProperty<Coin> getAmountProperty() {
|
||||
private ObjectProperty<BigInteger> getAmountProperty() {
|
||||
if (tradeAmountProperty == null)
|
||||
tradeAmountProperty = getAmount() != null ? new SimpleObjectProperty<>(getAmount()) : new SimpleObjectProperty<>();
|
||||
|
||||
@ -1730,9 +1730,9 @@ public abstract class Trade implements Tradable, Model {
|
||||
// set security deposits
|
||||
if (getBuyer().getSecurityDeposit() == 0) {
|
||||
BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
|
||||
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(HavenoUtils.coinToAtomicUnits(getAmount()));
|
||||
getBuyer().setSecurityDeposit(HavenoUtils.atomicUnitsToCentineros(buyerSecurityDeposit));
|
||||
getSeller().setSecurityDeposit(HavenoUtils.atomicUnitsToCentineros(sellerSecurityDeposit));
|
||||
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
|
||||
getBuyer().setSecurityDeposit(buyerSecurityDeposit.longValueExact());
|
||||
getSeller().setSecurityDeposit(sellerSecurityDeposit.longValueExact());
|
||||
}
|
||||
|
||||
// set deposits published state
|
||||
|
@ -22,12 +22,13 @@ import bisq.core.offer.Offer;
|
||||
import bisq.core.support.dispute.Dispute;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionInput;
|
||||
import org.bitcoinj.core.TransactionOutPoint;
|
||||
import org.bitcoinj.core.TransactionOutput;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import lombok.Getter;
|
||||
@ -130,7 +131,7 @@ public class TradeDataValidation {
|
||||
// Check amount
|
||||
TransactionOutput output = delayedPayoutTx.getOutput(0);
|
||||
Offer offer = checkNotNull(trade.getOffer());
|
||||
Coin msOutputAmount = offer.getBuyerSecurityDeposit()
|
||||
BigInteger msOutputAmount = offer.getBuyerSecurityDeposit()
|
||||
.add(offer.getSellerSecurityDeposit())
|
||||
.add(checkNotNull(trade.getAmount()));
|
||||
|
||||
|
@ -88,6 +88,8 @@ import javafx.collections.ObservableList;
|
||||
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@ -505,11 +507,11 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
// get expected taker fee
|
||||
Coin takerFee = HavenoUtils.getTakerFee(Coin.valueOf(offer.getOfferPayload().getAmount()));
|
||||
BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(offer.getOfferPayload().getAmount()));
|
||||
|
||||
// create arbitrator trade
|
||||
trade = new ArbitratorTrade(offer,
|
||||
Coin.valueOf(offer.getOfferPayload().getAmount()),
|
||||
BigInteger.valueOf(offer.getOfferPayload().getAmount()),
|
||||
takerFee,
|
||||
offer.getOfferPayload().getPrice(),
|
||||
xmrWalletService,
|
||||
@ -577,12 +579,12 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
openOfferManager.reserveOpenOffer(openOffer); // TODO (woodser): reserve offer if arbitrator? probably. or, arbitrator does not have open offer?
|
||||
|
||||
// get expected taker fee
|
||||
Coin takerFee = HavenoUtils.getTakerFee(Coin.valueOf(offer.getOfferPayload().getAmount()));
|
||||
BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(offer.getOfferPayload().getAmount()));
|
||||
|
||||
Trade trade;
|
||||
if (offer.isBuyOffer())
|
||||
trade = new BuyerAsMakerTrade(offer,
|
||||
Coin.valueOf(offer.getOfferPayload().getAmount()),
|
||||
BigInteger.valueOf(offer.getOfferPayload().getAmount()),
|
||||
takerFee,
|
||||
offer.getOfferPayload().getPrice(),
|
||||
xmrWalletService,
|
||||
@ -593,7 +595,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
request.getArbitratorNodeAddress());
|
||||
else
|
||||
trade = new SellerAsMakerTrade(offer,
|
||||
Coin.valueOf(offer.getOfferPayload().getAmount()),
|
||||
BigInteger.valueOf(offer.getOfferPayload().getAmount()),
|
||||
takerFee,
|
||||
offer.getOfferPayload().getPrice(),
|
||||
xmrWalletService,
|
||||
@ -742,9 +744,9 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
// First we check if offer is still available then we create the trade with the protocol
|
||||
public void onTakeOffer(Coin amount,
|
||||
Coin takerFee,
|
||||
Coin fundsNeededForTrade,
|
||||
public void onTakeOffer(BigInteger amount,
|
||||
BigInteger takerFee,
|
||||
BigInteger fundsNeededForTrade,
|
||||
Offer offer,
|
||||
String paymentAccountId,
|
||||
boolean useSavingsWallet,
|
||||
@ -786,7 +788,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
trade.getProcessModel().setTradeMessage(model.getTradeRequest());
|
||||
trade.getProcessModel().setMakerSignature(model.getMakerSignature());
|
||||
trade.getProcessModel().setUseSavingsWallet(useSavingsWallet);
|
||||
trade.getProcessModel().setFundsNeededForTradeAsLong(fundsNeededForTrade.value);
|
||||
trade.getProcessModel().setFundsNeededForTradeAsLong(fundsNeededForTrade.longValueExact());
|
||||
trade.getMaker().setPubKeyRing(trade.getOffer().getPubKeyRing());
|
||||
trade.getSelf().setPubKeyRing(model.getPubKeyRing());
|
||||
trade.getSelf().setPaymentAccountId(paymentAccountId);
|
||||
|
@ -23,7 +23,6 @@ import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.crypto.Sig;
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.messages.DepositRequest;
|
||||
import bisq.core.trade.messages.DepositResponse;
|
||||
@ -37,8 +36,6 @@ import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import monero.daemon.MoneroDaemon;
|
||||
import monero.daemon.model.MoneroSubmitTxResult;
|
||||
@ -79,9 +76,9 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
|
||||
Offer offer = trade.getOffer();
|
||||
boolean isFromTaker = trader == trade.getTaker();
|
||||
boolean isFromBuyer = trader == trade.getBuyer();
|
||||
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(isFromTaker ? trade.getTakerFee() : trade.getMakerFee());
|
||||
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(isFromBuyer ? Coin.ZERO : offer.getAmount());
|
||||
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit());
|
||||
BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
|
||||
BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount();
|
||||
BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
||||
String depositAddress = processModel.getMultisigAddress();
|
||||
|
||||
// verify deposit tx
|
||||
|
@ -20,14 +20,11 @@ package bisq.core.trade.protocol.tasks;
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.messages.InitTradeRequest;
|
||||
import bisq.core.trade.protocol.TradePeer;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
@ -55,9 +52,9 @@ public class ArbitratorProcessReserveTx extends TradeTask {
|
||||
// TODO (woodser): if signer online, should never be called by maker
|
||||
|
||||
// process reserve tx with expected values
|
||||
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(isFromTaker ? trade.getTakerFee() : trade.getMakerFee());
|
||||
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(isFromBuyer ? Coin.ZERO : offer.getAmount());
|
||||
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit());
|
||||
BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
|
||||
BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount();
|
||||
BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
||||
try {
|
||||
trade.getXmrWalletService().verifyTradeTx(
|
||||
tradeFee,
|
||||
|
@ -57,9 +57,9 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask {
|
||||
processModel.getOfferId(),
|
||||
request.getSenderNodeAddress(),
|
||||
request.getPubKeyRing(),
|
||||
trade.getAmount().value,
|
||||
trade.getAmount().longValueExact(),
|
||||
trade.getPrice().getValue(),
|
||||
trade.getTakerFee().getValue(),
|
||||
trade.getTakerFee().longValueExact(),
|
||||
request.getAccountId(),
|
||||
request.getPaymentAccountId(),
|
||||
request.getPaymentMethodId(),
|
||||
|
@ -24,11 +24,8 @@ import bisq.core.trade.messages.InitTradeRequest;
|
||||
import bisq.network.p2p.SendDirectMessageListener;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.crypto.Sig;
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -59,9 +56,9 @@ public class MakerSendInitTradeRequest extends TradeTask {
|
||||
offer.getId(),
|
||||
processModel.getMyNodeAddress(),
|
||||
processModel.getPubKeyRing(),
|
||||
offer.getAmount().value,
|
||||
offer.getAmount().longValueExact(),
|
||||
trade.getPrice().getValue(),
|
||||
offer.getMakerFee().value,
|
||||
offer.getMakerFee().longValueExact(),
|
||||
trade.getProcessModel().getAccountId(),
|
||||
offer.getMakerPaymentAccountId(),
|
||||
offer.getOfferPayload().getPaymentMethodId(),
|
||||
|
@ -27,7 +27,6 @@ import bisq.core.trade.messages.InitTradeRequest;
|
||||
import bisq.core.trade.protocol.TradePeer;
|
||||
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
@ -38,6 +37,7 @@ import static bisq.core.util.Validator.nonEmptyStringOf;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@ -134,7 +134,7 @@ public class ProcessInitTradeRequest extends TradeTask {
|
||||
|
||||
// check trade amount
|
||||
checkArgument(request.getTradeAmount() > 0);
|
||||
trade.setAmount(Coin.valueOf(request.getTradeAmount()));
|
||||
trade.setAmount(BigInteger.valueOf(request.getTradeAmount()));
|
||||
|
||||
// persist trade
|
||||
processModel.getTradeManager().requestPersistence();
|
||||
|
@ -20,14 +20,11 @@ package bisq.core.trade.protocol.tasks;
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import monero.daemon.model.MoneroOutput;
|
||||
import monero.wallet.model.MoneroTxWallet;
|
||||
|
||||
@ -43,9 +40,9 @@ public class TakerReserveTradeFunds extends TradeTask {
|
||||
runInterceptHook();
|
||||
|
||||
// create reserve tx
|
||||
BigInteger takerFee = HavenoUtils.coinToAtomicUnits(trade.getTakerFee());
|
||||
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getAmount() : Coin.ZERO);
|
||||
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getSellerSecurityDeposit() : trade.getOffer().getBuyerSecurityDeposit());
|
||||
BigInteger takerFee = trade.getTakerFee();
|
||||
BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getAmount() : BigInteger.valueOf(0);
|
||||
BigInteger securityDeposit = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getSellerSecurityDeposit() : trade.getOffer().getBuyerSecurityDeposit();
|
||||
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
|
||||
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(takerFee, sendAmount, securityDeposit, returnAddress);
|
||||
|
||||
|
@ -24,6 +24,7 @@ import bisq.core.monetary.Volume;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.offer.OfferPayload;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.util.JsonUtil;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
@ -44,12 +45,12 @@ import bisq.common.util.Utilities;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.ExchangeRate;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -144,7 +145,7 @@ public final class TradeStatistics2 implements ProcessOncePersistableNetworkPayl
|
||||
|
||||
public TradeStatistics2(OfferPayload offerPayload,
|
||||
Price tradePrice,
|
||||
Coin tradeAmount,
|
||||
BigInteger tradeAmount,
|
||||
Date tradeDate,
|
||||
String makerDepositTxId,
|
||||
String takerDepositTxId,
|
||||
@ -160,7 +161,7 @@ public final class TradeStatistics2 implements ProcessOncePersistableNetworkPayl
|
||||
offerPayload.getMinAmount(),
|
||||
offerPayload.getId(),
|
||||
tradePrice.getValue(),
|
||||
tradeAmount.value,
|
||||
tradeAmount.longValueExact(),
|
||||
tradeDate.getTime(),
|
||||
makerDepositTxId,
|
||||
takerDepositTxId,
|
||||
@ -312,15 +313,15 @@ public final class TradeStatistics2 implements ProcessOncePersistableNetworkPayl
|
||||
return baseCurrency.equals("XMR") ? counterCurrency : baseCurrency;
|
||||
}
|
||||
|
||||
public Coin getTradeAmount() {
|
||||
return Coin.valueOf(tradeAmount);
|
||||
public BigInteger getTradeAmount() {
|
||||
return BigInteger.valueOf(tradeAmount);
|
||||
}
|
||||
|
||||
public Volume getTradeVolume() {
|
||||
if (getPrice().getMonetary() instanceof Altcoin) {
|
||||
return new Volume(new AltcoinExchangeRate((Altcoin) getPrice().getMonetary()).coinToAltcoin(getTradeAmount()));
|
||||
return new Volume(new AltcoinExchangeRate((Altcoin) getPrice().getMonetary()).coinToAltcoin(HavenoUtils.atomicUnitsToCoin(getTradeAmount())));
|
||||
} else {
|
||||
Volume volume = new Volume(new ExchangeRate((Fiat) getPrice().getMonetary()).coinToFiat(getTradeAmount()));
|
||||
Volume volume = new Volume(new ExchangeRate((Fiat) getPrice().getMonetary()).coinToFiat(HavenoUtils.atomicUnitsToCoin(getTradeAmount())));
|
||||
return VolumeUtil.getRoundedFiatVolume(volume);
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ public class TradeStatisticsConverter {
|
||||
byte[] hash = tradeStatistics2.getHash();
|
||||
return new TradeStatistics3(tradeStatistics2.getCurrencyCode(),
|
||||
tradeStatistics2.getPrice().getValue(),
|
||||
tradeStatistics2.getTradeAmount().getValue(),
|
||||
tradeStatistics2.getTradeAmount().longValueExact(),
|
||||
tradeStatistics2.getOfferPaymentMethod(),
|
||||
time,
|
||||
mediator,
|
||||
|
@ -24,12 +24,12 @@ import bisq.core.monetary.Volume;
|
||||
|
||||
import bisq.common.util.MathUtils;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@ -65,12 +65,12 @@ public final class TradeStatisticsForJson {
|
||||
primaryMarketTradeAmount = getTradeVolume() != null ?
|
||||
getTradeVolume().getValue() :
|
||||
0;
|
||||
primaryMarketTradeVolume = getTradeAmount().getValue();
|
||||
primaryMarketTradeVolume = getTradeAmount().longValueExact();
|
||||
} else {
|
||||
currencyPair = Res.getBaseCurrencyCode() + "/" + currency;
|
||||
// we use precision 4 for fiat based price but on the markets api we use precision 8 so we scale up by 10000
|
||||
primaryMarketTradePrice = (long) MathUtils.scaleUpByPowerOf10(tradePrice.getValue(), 4);
|
||||
primaryMarketTradeAmount = getTradeAmount().getValue();
|
||||
primaryMarketTradeAmount = getTradeAmount().longValueExact();
|
||||
// we use precision 4 for fiat but on the markets api we use precision 8 so we scale up by 10000
|
||||
primaryMarketTradeVolume = getTradeVolume() != null ?
|
||||
(long) MathUtils.scaleUpByPowerOf10(getTradeVolume().getValue(), 4) :
|
||||
@ -86,8 +86,8 @@ public final class TradeStatisticsForJson {
|
||||
return Price.valueOf(currency, tradePrice);
|
||||
}
|
||||
|
||||
public Coin getTradeAmount() {
|
||||
return Coin.valueOf(tradeAmount);
|
||||
public BigInteger getTradeAmount() {
|
||||
return BigInteger.valueOf(tradeAmount);
|
||||
}
|
||||
|
||||
public Volume getTradeVolume() {
|
||||
|
@ -22,6 +22,7 @@ import bisq.core.locale.Res;
|
||||
import bisq.core.support.dispute.Dispute;
|
||||
import bisq.core.support.dispute.mediation.MediationManager;
|
||||
import bisq.core.support.dispute.refund.RefundManager;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.txproof.AssetTxProofRequestsPerTrade;
|
||||
import bisq.core.trade.txproof.AssetTxProofResult;
|
||||
@ -31,13 +32,12 @@ import bisq.network.Socks5ProxyProvider;
|
||||
|
||||
import bisq.common.handlers.FaultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -327,11 +327,11 @@ class XmrTxProofRequestsPerTrade implements AssetTxProofRequestsPerTrade {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private boolean isTradeAmountAboveLimit(Trade trade) {
|
||||
Coin tradeAmount = trade.getAmount();
|
||||
Coin tradeLimit = Coin.valueOf(autoConfirmSettings.getTradeLimit());
|
||||
if (tradeAmount != null && tradeAmount.isGreaterThan(tradeLimit)) {
|
||||
BigInteger tradeAmount = trade.getAmount();
|
||||
BigInteger tradeLimit = BigInteger.valueOf(autoConfirmSettings.getTradeLimit());
|
||||
if (tradeAmount != null && tradeAmount.compareTo(tradeLimit) > 0) {
|
||||
log.warn("Trade amount {} is higher than limit from auto-conf setting {}.",
|
||||
tradeAmount.toFriendlyString(), tradeLimit.toFriendlyString());
|
||||
HavenoUtils.formatToXmrWithCode(tradeAmount), HavenoUtils.formatToXmrWithCode(tradeLimit));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -20,6 +20,7 @@ package bisq.core.util.coin;
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.common.util.MathUtils;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
@ -29,6 +30,9 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import static bisq.core.util.VolumeUtil.getAdjustedFiatVolume;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class CoinUtil {
|
||||
|
||||
|
||||
@ -49,8 +53,8 @@ public class CoinUtil {
|
||||
* @param value Btc amount to be converted to percent value. E.g. 0.01 BTC is 1% (of 1 BTC)
|
||||
* @return The percentage value as double (e.g. 1% is 0.01)
|
||||
*/
|
||||
public static double getAsPercentPerBtc(Coin value) {
|
||||
return getAsPercentPerBtc(value, Coin.COIN);
|
||||
public static double getAsPercentPerBtc(BigInteger value) {
|
||||
return getAsPercentPerBtc(value, HavenoUtils.xmrToAtomicUnits(1.0));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,20 +64,20 @@ public class CoinUtil {
|
||||
*
|
||||
* @return The percentage value as double (e.g. 1% is 0.01)
|
||||
*/
|
||||
public static double getAsPercentPerBtc(Coin part, Coin total) {
|
||||
double asDouble = part != null ? (double) part.value : 0;
|
||||
double btcAsDouble = total != null ? (double) total.value : 1;
|
||||
return MathUtils.roundDouble(asDouble / btcAsDouble, 4);
|
||||
public static double getAsPercentPerBtc(BigInteger part, BigInteger total) {
|
||||
BigDecimal partDecimal = part == null ? BigDecimal.valueOf(0) : new BigDecimal(part);
|
||||
BigDecimal totalDecimal = total == null ? BigDecimal.valueOf(1) : new BigDecimal(total);
|
||||
return MathUtils.roundDouble(partDecimal.divide(totalDecimal).doubleValue(), 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param percent The percentage value as double (e.g. 1% is 0.01)
|
||||
* @param amount The amount as Coin for the percentage calculation
|
||||
* @return The percentage as Coin (e.g. 1% of 1 BTC is 0.01 BTC)
|
||||
* @param amount The amount as atomic units for the percentage calculation
|
||||
* @return The percentage as atomic units (e.g. 1% of 1 BTC is 0.01 BTC)
|
||||
*/
|
||||
public static Coin getPercentOfAmountAsCoin(double percent, Coin amount) {
|
||||
double amountAsDouble = amount != null ? (double) amount.value : 0;
|
||||
return Coin.valueOf(Math.round(percent * amountAsDouble));
|
||||
public static BigInteger getPercentOfAmount(double percent, BigInteger amount) {
|
||||
if (amount == null) amount = BigInteger.valueOf(0);
|
||||
return BigDecimal.valueOf(percent).multiply(new BigDecimal(amount)).toBigInteger();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,11 +89,11 @@ public class CoinUtil {
|
||||
* @param maxTradeLimit The max. trade limit of the users account, in satoshis.
|
||||
* @return The adjusted amount
|
||||
*/
|
||||
public static Coin getRoundedFiatAmount(Coin amount, Price price, long maxTradeLimit) {
|
||||
public static BigInteger getRoundedFiatAmount(BigInteger amount, Price price, long maxTradeLimit) {
|
||||
return getAdjustedAmount(amount, price, maxTradeLimit, 1);
|
||||
}
|
||||
|
||||
public static Coin getAdjustedAmountForHalCash(Coin amount, Price price, long maxTradeLimit) {
|
||||
public static BigInteger getAdjustedAmountForHalCash(BigInteger amount, Price price, long maxTradeLimit) {
|
||||
return getAdjustedAmount(amount, price, maxTradeLimit, 10);
|
||||
}
|
||||
|
||||
@ -97,7 +101,7 @@ public class CoinUtil {
|
||||
* Calculate the possibly adjusted amount for {@code amount}, taking into account the
|
||||
* {@code price} and {@code maxTradeLimit} and {@code factor}.
|
||||
*
|
||||
* @param amount Bitcoin amount which is a candidate for getting rounded.
|
||||
* @param amount amount which is a candidate for getting rounded.
|
||||
* @param price Price used in relation to that amount.
|
||||
* @param maxTradeLimit The max. trade limit of the users account, in satoshis.
|
||||
* @param factor The factor used for rounding. E.g. 1 means rounded to units of
|
||||
@ -105,10 +109,10 @@ public class CoinUtil {
|
||||
* @return The adjusted amount
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static Coin getAdjustedAmount(Coin amount, Price price, long maxTradeLimit, int factor) {
|
||||
static BigInteger getAdjustedAmount(BigInteger amount, Price price, long maxTradeLimit, int factor) {
|
||||
checkArgument(
|
||||
amount.getValue() >= 10_000,
|
||||
"amount needs to be above minimum of 10k satoshis"
|
||||
amount.longValueExact() >= HavenoUtils.xmrToAtomicUnits(0.0001).longValueExact(),
|
||||
"amount needs to be above minimum of 0.0001 xmr" // TODO: update amount for XMR
|
||||
);
|
||||
checkArgument(
|
||||
factor > 0,
|
||||
@ -118,17 +122,17 @@ public class CoinUtil {
|
||||
// 10 EUR in case of HalCash.
|
||||
Volume smallestUnitForVolume = Volume.parse(String.valueOf(factor), price.getCurrencyCode());
|
||||
if (smallestUnitForVolume.getValue() <= 0)
|
||||
return Coin.ZERO;
|
||||
return BigInteger.valueOf(0);
|
||||
|
||||
Coin smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume);
|
||||
long minTradeAmount = Restrictions.getMinTradeAmount().value;
|
||||
BigInteger smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume);
|
||||
long minTradeAmount = Restrictions.getMinTradeAmount().longValueExact();
|
||||
|
||||
// We use 10 000 satoshi as min allowed amount
|
||||
checkArgument(
|
||||
minTradeAmount >= 10_000,
|
||||
"MinTradeAmount must be at least 10k satoshis"
|
||||
minTradeAmount >= HavenoUtils.xmrToAtomicUnits(0.0001).longValueExact(),
|
||||
"MinTradeAmount must be at least 0.0001 xmr" // TODO: update amount for XMR
|
||||
);
|
||||
smallestUnitForAmount = Coin.valueOf(Math.max(minTradeAmount, smallestUnitForAmount.value));
|
||||
smallestUnitForAmount = BigInteger.valueOf(Math.max(minTradeAmount, smallestUnitForAmount.longValueExact()));
|
||||
// We don't allow smaller amount values than smallestUnitForAmount
|
||||
boolean useSmallestUnitForAmount = amount.compareTo(smallestUnitForAmount) < 0;
|
||||
|
||||
@ -137,21 +141,22 @@ public class CoinUtil {
|
||||
? getAdjustedFiatVolume(price.getVolumeByAmount(smallestUnitForAmount), factor)
|
||||
: getAdjustedFiatVolume(price.getVolumeByAmount(amount), factor);
|
||||
if (volume.getValue() <= 0)
|
||||
return Coin.ZERO;
|
||||
return BigInteger.valueOf(0);
|
||||
|
||||
// From that adjusted volume we calculate back the amount. It might be a bit different as
|
||||
// the amount used as input before due rounding.
|
||||
Coin amountByVolume = price.getAmountByVolume(volume);
|
||||
BigInteger amountByVolume = price.getAmountByVolume(volume);
|
||||
|
||||
// For the amount we allow only 4 decimal places
|
||||
long adjustedAmount = Math.round((double) amountByVolume.value / 10000d) * 10000;
|
||||
// TODO: remove rounding for XMR?
|
||||
long adjustedAmount = HavenoUtils.centinerosToAtomicUnits(Math.round((double) HavenoUtils.atomicUnitsToCentineros(amountByVolume) / 10000d) * 10000).longValueExact();
|
||||
|
||||
// If we are above our trade limit we reduce the amount by the smallestUnitForAmount
|
||||
while (adjustedAmount > maxTradeLimit) {
|
||||
adjustedAmount -= smallestUnitForAmount.value;
|
||||
adjustedAmount -= smallestUnitForAmount.longValueExact();
|
||||
}
|
||||
adjustedAmount = Math.max(minTradeAmount, adjustedAmount);
|
||||
adjustedAmount = Math.min(maxTradeLimit, adjustedAmount);
|
||||
return Coin.valueOf(adjustedAmount);
|
||||
return BigInteger.valueOf(adjustedAmount);
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +31,11 @@ import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.crypto.Sig;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPair;
|
||||
|
||||
import java.time.Instant;
|
||||
@ -354,7 +354,7 @@ public class SignedWitnessServiceTest {
|
||||
when(keyRing.getSignatureKeyPair()).thenReturn(signerKeyPair);
|
||||
|
||||
AccountAgeWitness accountAgeWitness = new AccountAgeWitness(account1DataHash, accountCreationTime);
|
||||
signedWitnessService.signAndPublishAccountAgeWitness(Coin.ZERO, accountAgeWitness, peerKeyPair.getPublic());
|
||||
signedWitnessService.signAndPublishAccountAgeWitness(BigInteger.valueOf(0), accountAgeWitness, peerKeyPair.getPublic());
|
||||
|
||||
verify(p2pService, never()).addPersistableNetworkPayload(any(PersistableNetworkPayload.class), anyBoolean());
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ import bisq.core.support.dispute.DisputeResult;
|
||||
import bisq.core.support.dispute.arbitration.TraderDataItem;
|
||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||
import bisq.core.trade.Contract;
|
||||
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.network.p2p.P2PService;
|
||||
import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
|
||||
|
||||
@ -44,7 +44,6 @@ import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.crypto.Sig;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
import java.security.KeyPair;
|
||||
@ -52,7 +51,6 @@ import java.security.PublicKey;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@ -227,7 +225,7 @@ public class AccountAgeWitnessServiceTest {
|
||||
when(chargeBackRisk.hasChargebackRisk(any(), any())).thenReturn(true);
|
||||
|
||||
when(contract.getPaymentMethodId()).thenReturn(PaymentMethod.SEPA_ID);
|
||||
when(contract.getTradeAmount()).thenReturn(Coin.parseCoin("0.01"));
|
||||
when(contract.getTradeAmount()).thenReturn(HavenoUtils.xmrToAtomicUnits(0.01));
|
||||
when(contract.getBuyerPubKeyRing()).thenReturn(buyerPubKeyRing);
|
||||
when(contract.getSellerPubKeyRing()).thenReturn(sellerPubKeyRing);
|
||||
when(contract.getOfferPayload()).thenReturn(mock(OfferPayload.class));
|
||||
@ -357,7 +355,7 @@ public class AccountAgeWitnessServiceTest {
|
||||
signerKeyRing.getSignatureKeyPair().getPublic().getEncoded(),
|
||||
witnessOwnerPubKey.getEncoded(),
|
||||
time,
|
||||
SignedWitnessService.MINIMUM_TRADE_AMOUNT_FOR_SIGNING.value);
|
||||
SignedWitnessService.MINIMUM_TRADE_AMOUNT_FOR_SIGNING.longValueExact());
|
||||
signedWitnessService.addToMap(signedWitness);
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,7 @@ import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.support.dispute.arbitration.TraderDataItem;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import org.junit.Before;
|
||||
@ -44,11 +43,11 @@ public class TraderDataItemTest {
|
||||
public void setup() {
|
||||
accountAgeWitness1 = new AccountAgeWitness(hash1, 123);
|
||||
accountAgeWitness2 = new AccountAgeWitness(hash2, 124);
|
||||
traderDataItem1 = new TraderDataItem(mock(PaymentAccountPayload.class), accountAgeWitness1, Coin.valueOf(546),
|
||||
traderDataItem1 = new TraderDataItem(mock(PaymentAccountPayload.class), accountAgeWitness1, BigInteger.valueOf(546),
|
||||
mock(PublicKey.class));
|
||||
traderDataItem2 = new TraderDataItem(mock(PaymentAccountPayload.class), accountAgeWitness1, Coin.valueOf(547),
|
||||
traderDataItem2 = new TraderDataItem(mock(PaymentAccountPayload.class), accountAgeWitness1, BigInteger.valueOf(547),
|
||||
mock(PublicKey.class));
|
||||
traderDataItem3 = new TraderDataItem(mock(PaymentAccountPayload.class), accountAgeWitness2, Coin.valueOf(548),
|
||||
traderDataItem3 = new TraderDataItem(mock(PaymentAccountPayload.class), accountAgeWitness2, BigInteger.valueOf(548),
|
||||
mock(PublicKey.class));
|
||||
}
|
||||
|
||||
|
@ -27,14 +27,16 @@ import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class CoinUtilTest {
|
||||
|
||||
@Test
|
||||
public void testGetFeePerBtc() {
|
||||
assertEquals(Coin.parseCoin("1"), HavenoUtils.getFeePerXmr(Coin.parseCoin("1"), Coin.parseCoin("1")));
|
||||
assertEquals(Coin.parseCoin("0.1"), HavenoUtils.getFeePerXmr(Coin.parseCoin("0.1"), Coin.parseCoin("1")));
|
||||
assertEquals(Coin.parseCoin("0.01"), HavenoUtils.getFeePerXmr(Coin.parseCoin("0.1"), Coin.parseCoin("0.1")));
|
||||
assertEquals(Coin.parseCoin("0.015"), HavenoUtils.getFeePerXmr(Coin.parseCoin("0.3"), Coin.parseCoin("0.05")));
|
||||
assertEquals(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.xmrToAtomicUnits(1)));
|
||||
assertEquals(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(1)));
|
||||
assertEquals(HavenoUtils.xmrToAtomicUnits(0.01), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1)));
|
||||
assertEquals(HavenoUtils.xmrToAtomicUnits(0.015), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.3), HavenoUtils.xmrToAtomicUnits(0.05)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -57,52 +59,52 @@ public class CoinUtilTest {
|
||||
|
||||
@Test
|
||||
public void testGetAdjustedAmount() {
|
||||
Coin result = CoinUtil.getAdjustedAmount(
|
||||
Coin.valueOf(100_000),
|
||||
BigInteger result = CoinUtil.getAdjustedAmount(
|
||||
HavenoUtils.xmrToAtomicUnits(0.001),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
20_000_000,
|
||||
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
|
||||
1);
|
||||
assertEquals(
|
||||
"Minimum trade amount allowed should be adjusted to the smallest trade allowed.",
|
||||
"0.001 BTC",
|
||||
result.toFriendlyString()
|
||||
"0.001 XMR",
|
||||
HavenoUtils.formatToXmrWithCode(result)
|
||||
);
|
||||
|
||||
try {
|
||||
CoinUtil.getAdjustedAmount(
|
||||
Coin.ZERO,
|
||||
BigInteger.valueOf(0),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
20_000_000,
|
||||
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
|
||||
1);
|
||||
fail("Expected IllegalArgumentException to be thrown when amount is too low.");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
assertEquals(
|
||||
"Unexpected exception message.",
|
||||
"amount needs to be above minimum of 10k satoshis",
|
||||
"amount needs to be above minimum of 0.0001 xmr",
|
||||
iae.getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
result = CoinUtil.getAdjustedAmount(
|
||||
Coin.valueOf(1_000_000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.01),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
20_000_000,
|
||||
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
|
||||
1);
|
||||
assertEquals(
|
||||
"Minimum allowed trade amount should not be adjusted.",
|
||||
"0.01 BTC",
|
||||
result.toFriendlyString()
|
||||
"0.01 XMR",
|
||||
HavenoUtils.formatToXmrWithCode(result)
|
||||
);
|
||||
|
||||
result = CoinUtil.getAdjustedAmount(
|
||||
Coin.valueOf(100_000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.001),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
1_000_000,
|
||||
HavenoUtils.xmrToAtomicUnits(0.1).longValueExact(),
|
||||
1);
|
||||
assertEquals(
|
||||
"Minimum trade amount allowed should respect maxTradeLimit and factor, if possible.",
|
||||
"0.001 BTC",
|
||||
result.toFriendlyString()
|
||||
"0.001 XMR",
|
||||
HavenoUtils.formatToXmrWithCode(result)
|
||||
);
|
||||
|
||||
// TODO(chirhonul): The following seems like it should raise an exception or otherwise fail.
|
||||
@ -111,14 +113,14 @@ public class CoinUtilTest {
|
||||
// 0.05 USD worth, which is below the factor of 1 USD, but does respect the maxTradeLimit.
|
||||
// Basically the given constraints (maxTradeLimit vs factor) are impossible to both fulfill..
|
||||
result = CoinUtil.getAdjustedAmount(
|
||||
Coin.valueOf(100_000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.001),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
5_000,
|
||||
HavenoUtils.xmrToAtomicUnits(0.00005).longValueExact(),
|
||||
1);
|
||||
assertEquals(
|
||||
"Minimum trade amount allowed with low maxTradeLimit should still respect that limit, even if result does not respect the factor specified.",
|
||||
"0.00005 BTC",
|
||||
result.toFriendlyString()
|
||||
"0.00005 XMR",
|
||||
HavenoUtils.formatToXmrWithCode(result)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package bisq.daemon.grpc;
|
||||
import bisq.core.api.CoreApi;
|
||||
import bisq.core.support.dispute.Attachment;
|
||||
import bisq.core.support.dispute.DisputeResult;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
|
||||
@ -108,9 +107,7 @@ public class GrpcDisputesService extends DisputesImplBase {
|
||||
try {
|
||||
var winner = ProtoUtil.enumFromProto(DisputeResult.Winner.class, req.getWinner().name());
|
||||
var reason = ProtoUtil.enumFromProto(DisputeResult.Reason.class, req.getReason().name());
|
||||
// scale atomic unit to centineros for consistency TODO switch base to atomic units?
|
||||
var customPayoutAmount = HavenoUtils.atomicUnitsToCentineros(req.getCustomPayoutAmount());
|
||||
coreApi.resolveDispute(req.getTradeId(), winner, reason, req.getSummaryNotes(), customPayoutAmount);
|
||||
coreApi.resolveDispute(req.getTradeId(), winner, reason, req.getSummaryNotes(), req.getCustomPayoutAmount());
|
||||
var reply = ResolveDisputeReply.newBuilder().build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
|
@ -21,7 +21,6 @@ import bisq.core.api.CoreApi;
|
||||
import bisq.core.api.model.OfferInfo;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.proto.grpc.CancelOfferReply;
|
||||
import bisq.proto.grpc.CancelOfferRequest;
|
||||
import bisq.proto.grpc.PostOfferReply;
|
||||
@ -154,8 +153,8 @@ class GrpcOffersService extends OffersImplBase {
|
||||
req.getPrice(),
|
||||
req.getUseMarketBasedPrice(),
|
||||
req.getMarketPriceMarginPct(),
|
||||
HavenoUtils.atomicUnitsToCentineros(req.getAmount()), // scale atomic unit to centineros for consistency TODO switch base to atomic units?
|
||||
HavenoUtils.atomicUnitsToCentineros(req.getMinAmount()),
|
||||
req.getAmount(),
|
||||
req.getMinAmount(),
|
||||
req.getBuyerSecurityDepositPct(),
|
||||
req.getTriggerPrice(),
|
||||
req.getPaymentAccountId(),
|
||||
|
@ -37,8 +37,6 @@ import bisq.proto.grpc.SendChatMessageReply;
|
||||
import bisq.proto.grpc.SendChatMessageRequest;
|
||||
import bisq.proto.grpc.TakeOfferReply;
|
||||
import bisq.proto.grpc.TakeOfferRequest;
|
||||
import bisq.proto.grpc.WithdrawFundsReply;
|
||||
import bisq.proto.grpc.WithdrawFundsRequest;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
|
||||
@ -191,19 +189,6 @@ class GrpcTradesService extends TradesImplBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withdrawFunds(WithdrawFundsRequest req,
|
||||
StreamObserver<WithdrawFundsReply> responseObserver) {
|
||||
try {
|
||||
coreApi.withdrawFunds(req.getTradeId(), req.getAddress(), req.getMemo());
|
||||
var reply = WithdrawFundsReply.newBuilder().build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getChatMessages(GetChatMessagesRequest req,
|
||||
StreamObserver<GetChatMessagesReply> responseObserver) {
|
||||
|
@ -25,7 +25,7 @@ import bisq.desktop.util.GUIUtil;
|
||||
import bisq.core.account.sign.SignedWitnessService;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.OfferRestrictions;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
|
||||
@ -54,14 +54,13 @@ public class AccountStatusTooltipLabel extends AutoTooltipLabel {
|
||||
private PopOver popOver;
|
||||
private boolean keepPopOverVisible = false;
|
||||
|
||||
public AccountStatusTooltipLabel(OfferBookListItem.WitnessAgeData witnessAgeData,
|
||||
CoinFormatter formatter) {
|
||||
public AccountStatusTooltipLabel(OfferBookListItem.WitnessAgeData witnessAgeData) {
|
||||
super(witnessAgeData.getDisplayString());
|
||||
this.witnessAgeData = witnessAgeData;
|
||||
this.textIcon = FormBuilder.getIcon(witnessAgeData.getIcon());
|
||||
this.popupTitle = witnessAgeData.isLimitLifted()
|
||||
? Res.get("offerbook.timeSinceSigning.tooltip.accountLimitLifted")
|
||||
: Res.get("offerbook.timeSinceSigning.tooltip.accountLimit", formatter.formatCoinWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT));
|
||||
: Res.get("offerbook.timeSinceSigning.tooltip.accountLimit", HavenoUtils.formatToXmrWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT));
|
||||
|
||||
positionAndActivateIcon();
|
||||
}
|
||||
|
@ -21,11 +21,9 @@ import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
@ -40,6 +38,7 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.URI;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -50,7 +49,7 @@ public class AddressTextField extends AnchorPane {
|
||||
|
||||
private final StringProperty address = new SimpleStringProperty();
|
||||
private final StringProperty paymentLabel = new SimpleStringProperty();
|
||||
private final ObjectProperty<Coin> amountAsCoin = new SimpleObjectProperty<>(Coin.ZERO);
|
||||
private final ObjectProperty<BigInteger> amount = new SimpleObjectProperty<>(BigInteger.ZERO);
|
||||
private boolean wasPrimaryButtonDown;
|
||||
|
||||
|
||||
@ -128,16 +127,16 @@ public class AddressTextField extends AnchorPane {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Coin getAmountAsCoin() {
|
||||
return amountAsCoin.get();
|
||||
public BigInteger getAmount() {
|
||||
return amount.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<Coin> amountAsCoinProperty() {
|
||||
return amountAsCoin;
|
||||
public ObjectProperty<BigInteger> amountAsProperty() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmountAsCoin(Coin amountAsCoin) {
|
||||
this.amountAsCoin.set(amountAsCoin);
|
||||
public void setAmount(BigInteger amount) {
|
||||
this.amount.set(amount);
|
||||
}
|
||||
|
||||
public String getPaymentLabel() {
|
||||
@ -158,11 +157,11 @@ public class AddressTextField extends AnchorPane {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private String getBitcoinURI() {
|
||||
if (amountAsCoin.get().isNegative()) {
|
||||
if (amount.get().compareTo(BigInteger.valueOf(0)) < 0) {
|
||||
log.warn("Amount must not be negative");
|
||||
setAmountAsCoin(Coin.ZERO);
|
||||
setAmount(BigInteger.valueOf(0));
|
||||
}
|
||||
return GUIUtil.getBitcoinURI(address.get(), amountAsCoin.get(),
|
||||
return GUIUtil.getBitcoinURI(address.get(), HavenoUtils.atomicUnitsToCoin(amount.get()),
|
||||
paymentLabel.get());
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,9 @@
|
||||
|
||||
package bisq.desktop.components;
|
||||
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
|
||||
import javafx.scene.effect.BlurType;
|
||||
@ -29,17 +28,19 @@ import javafx.scene.effect.Effect;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BalanceTextField extends AnchorPane {
|
||||
|
||||
private Coin targetAmount;
|
||||
private BigInteger targetAmount;
|
||||
private final JFXTextField textField;
|
||||
private final Effect fundedEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.GREEN, 4, 0.0, 0, 0);
|
||||
private final Effect notFundedEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.ORANGERED, 4, 0.0, 0, 0);
|
||||
private CoinFormatter formatter;
|
||||
@Nullable
|
||||
private Coin balance;
|
||||
private BigInteger balance;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -64,13 +65,13 @@ public class BalanceTextField extends AnchorPane {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
public void setBalance(Coin balance) {
|
||||
public void setBalance(BigInteger balance) {
|
||||
this.balance = balance;
|
||||
|
||||
updateBalance(balance);
|
||||
}
|
||||
|
||||
public void setTargetAmount(Coin targetAmount) {
|
||||
public void setTargetAmount(BigInteger targetAmount) {
|
||||
this.targetAmount = targetAmount;
|
||||
|
||||
if (this.balance != null)
|
||||
@ -81,9 +82,9 @@ public class BalanceTextField extends AnchorPane {
|
||||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void updateBalance(Coin balance) {
|
||||
private void updateBalance(BigInteger balance) {
|
||||
if (formatter != null)
|
||||
textField.setText(formatter.formatCoinWithCode(balance));
|
||||
textField.setText(HavenoUtils.formatToXmrWithCode(balance));
|
||||
|
||||
//TODO: replace with new validation logic
|
||||
// if (targetAmount != null) {
|
||||
|
@ -238,7 +238,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||
|
||||
Tuple2<Label, VBox> availableBalanceBox = getBalanceBox(Res.get("mainView.balance.available"));
|
||||
availableBalanceBox.first.textProperty().bind(model.getAvailableBalance());
|
||||
availableBalanceBox.first.setPrefWidth(100);
|
||||
availableBalanceBox.first.setPrefWidth(105);
|
||||
availableBalanceBox.first.tooltipProperty().bind(new ObjectBinding<>() {
|
||||
{
|
||||
bind(model.getAvailableBalance());
|
||||
|
@ -115,6 +115,7 @@ import bisq.core.payment.validation.TransferwiseValidator;
|
||||
import bisq.core.payment.validation.USPostalMoneyOrderValidator;
|
||||
import bisq.core.payment.validation.UpholdValidator;
|
||||
import bisq.core.payment.validation.WeChatPayValidator;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
@ -123,8 +124,6 @@ import bisq.common.util.Tuple2;
|
||||
import bisq.common.util.Tuple3;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@ -142,6 +141,7 @@ import javafx.collections.ObservableList;
|
||||
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -257,9 +257,9 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void onSaveNewAccount(PaymentAccount paymentAccount) {
|
||||
Coin maxTradeLimitAsCoin = paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin("USD");
|
||||
Coin maxTradeLimitSecondMonth = maxTradeLimitAsCoin.divide(2L);
|
||||
Coin maxTradeLimitFirstMonth = maxTradeLimitAsCoin.divide(4L);
|
||||
BigInteger maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimit("USD");
|
||||
BigInteger maxTradeLimitSecondMonth = maxTradeLimit.divide(BigInteger.valueOf(2L));
|
||||
BigInteger maxTradeLimitFirstMonth = maxTradeLimit.divide(BigInteger.valueOf(4L));
|
||||
if (paymentAccount instanceof F2FAccount) {
|
||||
new Popup().information(Res.get("payment.f2f.info"))
|
||||
.width(700)
|
||||
@ -287,17 +287,17 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
|
||||
} else {
|
||||
|
||||
String limitsInfoKey = "payment.limits.info";
|
||||
String initialLimit = formatter.formatCoinWithCode(maxTradeLimitFirstMonth);
|
||||
String initialLimit = HavenoUtils.formatToXmrWithCode(maxTradeLimitFirstMonth);
|
||||
|
||||
if (PaymentMethod.hasChargebackRisk(paymentAccount.getPaymentMethod(), paymentAccount.getTradeCurrencies())) {
|
||||
limitsInfoKey = "payment.limits.info.withSigning";
|
||||
initialLimit = formatter.formatCoinWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT);
|
||||
initialLimit = HavenoUtils.formatToXmrWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT);
|
||||
}
|
||||
|
||||
new Popup().information(Res.get(limitsInfoKey,
|
||||
initialLimit,
|
||||
formatter.formatCoinWithCode(maxTradeLimitSecondMonth),
|
||||
formatter.formatCoinWithCode(maxTradeLimitAsCoin)))
|
||||
HavenoUtils.formatToXmrWithCode(maxTradeLimitSecondMonth),
|
||||
HavenoUtils.formatToXmrWithCode(maxTradeLimit)))
|
||||
.width(700)
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.actionButtonText(Res.get("shared.iUnderstand"))
|
||||
|
@ -37,14 +37,13 @@ import monero.daemon.model.MoneroTx;
|
||||
import monero.wallet.model.MoneroTransferQuery;
|
||||
import monero.wallet.model.MoneroTxQuery;
|
||||
import monero.wallet.model.MoneroTxWallet;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
@Slf4j
|
||||
class DepositListItem {
|
||||
private final StringProperty balance = new SimpleStringProperty();
|
||||
private final XmrAddressEntry addressEntry;
|
||||
private final XmrWalletService xmrWalletService;
|
||||
private Coin balanceAsCoin;
|
||||
private BigInteger balanceAsBI;
|
||||
private String usage = "-";
|
||||
private XmrBalanceListener balanceListener;
|
||||
private int numTxOutputs = 0;
|
||||
@ -66,15 +65,15 @@ class DepositListItem {
|
||||
balanceListener = new XmrBalanceListener(addressEntry.getSubaddressIndex()) {
|
||||
@Override
|
||||
public void onBalanceChanged(BigInteger balance) {
|
||||
DepositListItem.this.balanceAsCoin = HavenoUtils.atomicUnitsToCoin(balance);
|
||||
DepositListItem.this.balance.set(formatter.formatCoin(balanceAsCoin));
|
||||
DepositListItem.this.balanceAsBI = balance;
|
||||
DepositListItem.this.balance.set(HavenoUtils.formatToXmr(balanceAsBI));
|
||||
updateUsage(addressEntry.getSubaddressIndex(), null);
|
||||
}
|
||||
};
|
||||
xmrWalletService.addBalanceListener(balanceListener);
|
||||
|
||||
balanceAsCoin = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
||||
balance.set(formatter.formatCoin(balanceAsCoin));
|
||||
balanceAsBI = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
||||
balance.set(HavenoUtils.formatToXmr(balanceAsBI));
|
||||
|
||||
updateUsage(addressEntry.getSubaddressIndex(), cachedTxs);
|
||||
|
||||
@ -124,8 +123,8 @@ class DepositListItem {
|
||||
return balance.get();
|
||||
}
|
||||
|
||||
public Coin getBalanceAsCoin() {
|
||||
return balanceAsCoin;
|
||||
public BigInteger getBalanceAsBI() {
|
||||
return balanceAsBI;
|
||||
}
|
||||
|
||||
public int getNumTxOutputs() {
|
||||
|
@ -157,7 +157,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||
setConfidenceColumnCellFactory();
|
||||
|
||||
addressColumn.setComparator(Comparator.comparing(DepositListItem::getAddressString));
|
||||
balanceColumn.setComparator(Comparator.comparing(DepositListItem::getBalanceAsCoin));
|
||||
balanceColumn.setComparator(Comparator.comparing(DepositListItem::getBalanceAsBI));
|
||||
confirmationsColumn.setComparator(Comparator.comparingLong(o -> o.getNumConfirmationsSinceFirstUsed()));
|
||||
usageColumn.setComparator(Comparator.comparingInt(DepositListItem::getNumTxOutputs));
|
||||
tableView.getSortOrder().add(usageColumn);
|
||||
@ -237,7 +237,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||
|
||||
xmrWalletService.addBalanceListener(balanceListener);
|
||||
amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> {
|
||||
addressTextField.setAmountAsCoin(ParsingUtils.parseToCoin(t, formatter));
|
||||
addressTextField.setAmount(HavenoUtils.parseXmr(t));
|
||||
updateQRCode();
|
||||
});
|
||||
|
||||
@ -306,7 +306,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||
.forEach(e -> observableList.add(new DepositListItem(e, xmrWalletService, formatter, incomingTxs)));
|
||||
}
|
||||
|
||||
private Coin getAmountAsCoin() {
|
||||
private Coin getAmount() {
|
||||
return ParsingUtils.parseToCoin(amountTextField.getText(), formatter);
|
||||
}
|
||||
|
||||
@ -314,7 +314,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||
private String getPaymentUri() {
|
||||
return xmrWalletService.getWallet().getPaymentUri(new MoneroTxConfig()
|
||||
.setAddress(addressTextField.getAddress())
|
||||
.setAmount(HavenoUtils.coinToAtomicUnits(getAmountAsCoin()))
|
||||
.setAmount(HavenoUtils.coinToAtomicUnits(getAmount()))
|
||||
.setNote(paymentLabelString));
|
||||
}
|
||||
|
||||
|
@ -51,8 +51,6 @@ public class TransactionListItemFactory {
|
||||
TransactionsListItem create(MoneroTxWallet transaction, @Nullable TransactionAwareTradable tradable) {
|
||||
return new TransactionsListItem(transaction,
|
||||
xmrWalletService,
|
||||
tradable,
|
||||
formatter,
|
||||
preferences.getIgnoreDustThreshold());
|
||||
tradable);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Tradable;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
@ -41,11 +40,9 @@ import monero.wallet.model.MoneroIncomingTransfer;
|
||||
import monero.wallet.model.MoneroOutgoingTransfer;
|
||||
import monero.wallet.model.MoneroTxWallet;
|
||||
import monero.wallet.model.MoneroWalletListener;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
@Slf4j
|
||||
class TransactionsListItem {
|
||||
private final CoinFormatter formatter;
|
||||
private String dateString;
|
||||
private final Date date;
|
||||
private final String txId;
|
||||
@ -56,11 +53,10 @@ class TransactionsListItem {
|
||||
private String direction = "";
|
||||
private boolean received;
|
||||
private boolean detailsAvailable;
|
||||
private Coin amountAsCoin = Coin.ZERO;
|
||||
private BigInteger amount = BigInteger.valueOf(0);
|
||||
private String memo = "";
|
||||
private long confirmations = 0;
|
||||
@Getter
|
||||
private final boolean isDustAttackTx;
|
||||
private boolean initialTxConfidenceVisibility = true;
|
||||
private final Supplier<LazyFields> lazyFieldsSupplier;
|
||||
|
||||
@ -77,25 +73,20 @@ class TransactionsListItem {
|
||||
TransactionsListItem() {
|
||||
date = null;
|
||||
txId = null;
|
||||
formatter = null;
|
||||
isDustAttackTx = false;
|
||||
lazyFieldsSupplier = null;
|
||||
}
|
||||
|
||||
TransactionsListItem(MoneroTxWallet tx,
|
||||
XmrWalletService xmrWalletService,
|
||||
TransactionAwareTradable transactionAwareTradable,
|
||||
CoinFormatter formatter,
|
||||
long ignoreDustThreshold) {
|
||||
this.formatter = formatter;
|
||||
TransactionAwareTradable transactionAwareTradable) {
|
||||
this.memo = tx.getNote();
|
||||
this.txId = tx.getHash();
|
||||
|
||||
Optional<Tradable> optionalTradable = Optional.ofNullable(transactionAwareTradable)
|
||||
.map(TransactionAwareTradable::asTradable);
|
||||
|
||||
Coin valueSentToMe = HavenoUtils.atomicUnitsToCoin(tx.getIncomingAmount() == null ? new BigInteger("0") : tx.getIncomingAmount());
|
||||
Coin valueSentFromMe = HavenoUtils.atomicUnitsToCoin(tx.getOutgoingAmount() == null ? new BigInteger("0") : tx.getOutgoingAmount());
|
||||
BigInteger valueSentToMe = tx.getIncomingAmount() == null ? new BigInteger("0") : tx.getIncomingAmount();
|
||||
BigInteger valueSentFromMe = tx.getOutgoingAmount() == null ? new BigInteger("0") : tx.getOutgoingAmount();
|
||||
|
||||
if (tx.getTransfers().get(0).isIncoming()) {
|
||||
addressString = ((MoneroIncomingTransfer) tx.getTransfers().get(0)).getAddress();
|
||||
@ -105,12 +96,12 @@ class TransactionsListItem {
|
||||
else addressString = "unavailable";
|
||||
}
|
||||
|
||||
if (valueSentFromMe.isZero()) {
|
||||
amountAsCoin = valueSentToMe;
|
||||
if (valueSentFromMe.compareTo(BigInteger.valueOf(0)) == 0) {
|
||||
amount = valueSentToMe;
|
||||
direction = Res.get("funds.tx.direction.receivedWith");
|
||||
received = true;
|
||||
} else {
|
||||
amountAsCoin = valueSentFromMe.multiply(-1);
|
||||
amount = valueSentFromMe.multiply(BigInteger.valueOf(-1));
|
||||
received = false;
|
||||
direction = Res.get("funds.tx.direction.sentTo");
|
||||
}
|
||||
@ -134,13 +125,13 @@ class TransactionsListItem {
|
||||
} else if (trade.getPayoutTxId() != null &&
|
||||
trade.getPayoutTxId().equals(txId)) {
|
||||
details = Res.get("funds.tx.multiSigPayout", tradeId);
|
||||
if (amountAsCoin.isZero()) {
|
||||
if (amount.compareTo(BigInteger.valueOf(0)) == 0) {
|
||||
initialTxConfidenceVisibility = false;
|
||||
}
|
||||
} else {
|
||||
Trade.DisputeState disputeState = trade.getDisputeState();
|
||||
if (disputeState == Trade.DisputeState.DISPUTE_CLOSED) {
|
||||
if (valueSentToMe.isPositive()) {
|
||||
if (valueSentToMe.compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
details = Res.get("funds.tx.disputePayout", tradeId);
|
||||
} else {
|
||||
details = Res.get("funds.tx.disputeLost", tradeId);
|
||||
@ -148,7 +139,7 @@ class TransactionsListItem {
|
||||
} else if (disputeState == Trade.DisputeState.REFUND_REQUEST_CLOSED ||
|
||||
disputeState == Trade.DisputeState.REFUND_REQUESTED ||
|
||||
disputeState == Trade.DisputeState.REFUND_REQUEST_STARTED_BY_PEER) {
|
||||
if (valueSentToMe.isPositive()) {
|
||||
if (valueSentToMe.compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
details = Res.get("funds.tx.refund", tradeId);
|
||||
} else {
|
||||
// We have spent the deposit tx outputs to the Bisq donation address to enable
|
||||
@ -156,7 +147,7 @@ class TransactionsListItem {
|
||||
// already when funding the deposit tx we show 0 BTC as amount.
|
||||
// Confirmation is not known from the BitcoinJ side (not 100% clear why) as no funds
|
||||
// left our wallet nor we received funds. So we set indicator invisible.
|
||||
amountAsCoin = Coin.ZERO;
|
||||
amount = BigInteger.valueOf(0);
|
||||
details = Res.get("funds.tx.collateralForRefund", tradeId);
|
||||
initialTxConfidenceVisibility = false;
|
||||
}
|
||||
@ -166,7 +157,7 @@ class TransactionsListItem {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (amountAsCoin.isZero()) {
|
||||
if (amount.compareTo(BigInteger.valueOf(0)) == 0) {
|
||||
details = Res.get("funds.tx.noFundsFromDispute");
|
||||
}
|
||||
}
|
||||
@ -176,11 +167,6 @@ class TransactionsListItem {
|
||||
this.date = new Date(timestamp);
|
||||
dateString = DisplayUtils.formatDateTime(date);
|
||||
|
||||
isDustAttackTx = received && valueSentToMe.value < ignoreDustThreshold;
|
||||
if (isDustAttackTx) {
|
||||
details = Res.get("funds.tx.dustAttackTx");
|
||||
}
|
||||
|
||||
// confidence
|
||||
lazyFieldsSupplier = Suppliers.memoize(() -> new LazyFields() {{
|
||||
txConfidenceIndicator = new TxConfidenceIndicator();
|
||||
@ -217,16 +203,14 @@ class TransactionsListItem {
|
||||
return dateString;
|
||||
}
|
||||
|
||||
|
||||
public String getAmount() {
|
||||
return formatter.formatCoin(amountAsCoin);
|
||||
public String getAmountStr() {
|
||||
return HavenoUtils.formatToXmr(amount);
|
||||
}
|
||||
|
||||
public Coin getAmountAsCoin() {
|
||||
return amountAsCoin;
|
||||
public BigInteger getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
||||
public String getAddressString() {
|
||||
return addressString;
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.ExternalHyperlink;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
@ -168,7 +167,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
});
|
||||
addressColumn.setComparator(Comparator.comparing(item -> item.getDirection() + item.getAddressString()));
|
||||
transactionColumn.setComparator(Comparator.comparing(TransactionsListItem::getTxId));
|
||||
amountColumn.setComparator(Comparator.comparing(TransactionsListItem::getAmountAsCoin));
|
||||
amountColumn.setComparator(Comparator.comparing(TransactionsListItem::getAmount));
|
||||
confidenceColumn.setComparator(Comparator.comparingLong(item -> item.getNumConfirmations()));
|
||||
memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo));
|
||||
|
||||
@ -221,7 +220,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
columns[1] = item.getDetails();
|
||||
columns[2] = item.getDirection() + " " + item.getAddressString();
|
||||
columns[3] = item.getTxId();
|
||||
columns[4] = item.getAmount();
|
||||
columns[4] = item.getAmountStr();
|
||||
columns[5] = item.getMemo() == null ? "" : item.getMemo();
|
||||
columns[6] = String.valueOf(item.getNumConfirmations());
|
||||
return columns;
|
||||
@ -320,13 +319,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
setGraphic(hyperlinkWithIcon);
|
||||
// If details are available its a trade tx and we don't expect any dust attack tx
|
||||
} else {
|
||||
if (item.isDustAttackTx()) {
|
||||
hyperlinkWithIcon = new HyperlinkWithIcon(item.getDetails(), AwesomeIcon.WARNING_SIGN);
|
||||
hyperlinkWithIcon.setOnAction(event -> new Popup().warning(Res.get("funds.tx.dustAttackTx.popup")).show());
|
||||
setGraphic(hyperlinkWithIcon);
|
||||
} else {
|
||||
setGraphic(new AutoTooltipLabel(item.getDetails()));
|
||||
}
|
||||
setGraphic(new AutoTooltipLabel(item.getDetails()));
|
||||
}
|
||||
} else {
|
||||
setGraphic(null);
|
||||
@ -423,7 +416,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getAmount()));
|
||||
setGraphic(new AutoTooltipLabel(item.getAmountStr()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -23,11 +23,9 @@ import bisq.core.btc.listeners.XmrBalanceListener;
|
||||
import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@ -41,7 +39,7 @@ class WithdrawalListItem {
|
||||
private final XmrAddressEntry addressEntry;
|
||||
private final XmrWalletService walletService;
|
||||
private final CoinFormatter formatter;
|
||||
private Coin balance;
|
||||
private BigInteger balance;
|
||||
private final String addressString;
|
||||
@Setter
|
||||
@Getter
|
||||
@ -74,7 +72,7 @@ class WithdrawalListItem {
|
||||
private void updateBalance() {
|
||||
balance = walletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
||||
if (balance != null)
|
||||
balanceLabel.setText(formatter.formatCoin(this.balance));
|
||||
balanceLabel.setText(HavenoUtils.formatToXmr(this.balance));
|
||||
}
|
||||
|
||||
public final String getLabel() {
|
||||
@ -111,7 +109,7 @@ class WithdrawalListItem {
|
||||
return balanceLabel;
|
||||
}
|
||||
|
||||
public Coin getBalance() {
|
||||
public BigInteger getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
|
@ -35,18 +35,12 @@ import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.core.util.validation.BtcAddressValidator;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import monero.wallet.model.MoneroTxConfig;
|
||||
import monero.wallet.model.MoneroTxWallet;
|
||||
|
||||
@ -78,9 +72,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
private final XmrWalletService xmrWalletService;
|
||||
private final TradeManager tradeManager;
|
||||
private final P2PService p2PService;
|
||||
private final CoinFormatter formatter;
|
||||
private XmrBalanceListener balanceListener;
|
||||
private Coin amountAsCoin = Coin.ZERO;
|
||||
private BigInteger amount = BigInteger.valueOf(0);
|
||||
private ChangeListener<String> amountListener;
|
||||
private ChangeListener<Boolean> amountFocusListener;
|
||||
private int rowIndex = 0;
|
||||
@ -94,13 +87,11 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
TradeManager tradeManager,
|
||||
P2PService p2PService,
|
||||
WalletsSetup walletsSetup,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
BtcAddressValidator btcAddressValidator,
|
||||
WalletPasswordWindow walletPasswordWindow) {
|
||||
this.xmrWalletService = xmrWalletService;
|
||||
this.tradeManager = tradeManager;
|
||||
this.p2PService = p2PService;
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -136,7 +127,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
amountListener = (observable, oldValue, newValue) -> {
|
||||
if (amountTextField.focusedProperty().get()) {
|
||||
try {
|
||||
amountAsCoin = ParsingUtils.parseToCoin(amountTextField.getText(), formatter);
|
||||
amount = HavenoUtils.parseXmr(amountTextField.getText());
|
||||
} catch (Throwable t) {
|
||||
log.error("Error at amountTextField input. " + t.toString());
|
||||
}
|
||||
@ -144,8 +135,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
};
|
||||
amountFocusListener = (observable, oldValue, newValue) -> {
|
||||
if (oldValue && !newValue) {
|
||||
if (amountAsCoin.isPositive())
|
||||
amountTextField.setText(formatter.formatCoin(amountAsCoin));
|
||||
if (amount.compareTo(BigInteger.valueOf(0)) > 0)
|
||||
amountTextField.setText(HavenoUtils.formatToXmr(amount));
|
||||
else
|
||||
amountTextField.setText("");
|
||||
}
|
||||
@ -184,23 +175,23 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
final String withdrawToAddress = withdrawToTextField.getText();
|
||||
|
||||
// get receiver amount
|
||||
Coin receiverAmount = amountAsCoin;
|
||||
if (!receiverAmount.isPositive()) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow"));
|
||||
BigInteger receiverAmount = amount;
|
||||
if (receiverAmount.compareTo(BigInteger.valueOf(0)) <= 0) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow"));
|
||||
|
||||
// create tx
|
||||
MoneroTxWallet tx = xmrWalletService.getWallet().createTx(new MoneroTxConfig()
|
||||
.setAccountIndex(0)
|
||||
.setAmount(HavenoUtils.coinToAtomicUnits(receiverAmount)) // TODO: rename to centinerosToAtomicUnits()?
|
||||
.setAmount(receiverAmount)
|
||||
.setAddress(withdrawToAddress));
|
||||
|
||||
// create confirmation message
|
||||
Coin sendersAmount = receiverAmount;
|
||||
Coin fee = HavenoUtils.atomicUnitsToCoin(tx.getFee());
|
||||
BigInteger sendersAmount = receiverAmount;
|
||||
BigInteger fee = tx.getFee();
|
||||
String messageText = Res.get("shared.sendFundsDetailsWithFee",
|
||||
formatter.formatCoinWithCode(sendersAmount),
|
||||
HavenoUtils.formatToXmrWithCode(sendersAmount),
|
||||
withdrawToAddress,
|
||||
formatter.formatCoinWithCode(fee),
|
||||
formatter.formatCoinWithCode(receiverAmount));
|
||||
HavenoUtils.formatToXmrWithCode(fee),
|
||||
HavenoUtils.formatToXmrWithCode(receiverAmount));
|
||||
|
||||
// popup confirmation message
|
||||
new Popup().headLine(Res.get("funds.withdrawal.confirmWithdrawalRequest"))
|
||||
@ -214,7 +205,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
xmrWalletService.getWallet().setTxNote(tx.getHash(), withdrawMemoTextField.getText()); // TODO (monero-java): tx note does not persist when tx created then relayed
|
||||
String key = "showTransactionSent";
|
||||
if (DontShowAgainLookup.showAgain(key)) {
|
||||
new TxDetails(tx.getHash(), withdrawToAddress, formatter.formatCoinWithCode(sendersAmount), formatter.formatCoinWithCode(fee), xmrWalletService.getWallet().getTxNote(tx.getHash()))
|
||||
new TxDetails(tx.getHash(), withdrawToAddress, HavenoUtils.formatToXmrWithCode(sendersAmount), HavenoUtils.formatToXmrWithCode(fee), xmrWalletService.getWallet().getTxNote(tx.getHash()))
|
||||
.dontShowAgainId(key)
|
||||
.show();
|
||||
}
|
||||
@ -225,7 +216,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
.filter(Trade::isPayoutPublished)
|
||||
.forEach(trade -> xmrWalletService.getAddressEntry(trade.getId(), XmrAddressEntry.Context.TRADE_PAYOUT)
|
||||
.ifPresent(addressEntry -> {
|
||||
if (xmrWalletService.getBalanceForAddress(addressEntry.getAddressString()).isZero())
|
||||
if (xmrWalletService.getBalanceForAddress(addressEntry.getAddressString()).compareTo(BigInteger.valueOf(0)) == 0)
|
||||
tradeManager.onTradeCompleted(trade);
|
||||
}));
|
||||
} catch (Exception e) {
|
||||
@ -251,7 +242,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void reset() {
|
||||
amountAsCoin = Coin.ZERO;
|
||||
amount = BigInteger.valueOf(0);
|
||||
amountTextField.setText("");
|
||||
amountTextField.setPromptText(Res.get("funds.withdrawal.setAmount"));
|
||||
|
||||
|
@ -32,7 +32,6 @@ import bisq.desktop.util.CurrencyList;
|
||||
import bisq.desktop.util.CurrencyListItem;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.GlobalSettings;
|
||||
@ -67,7 +66,6 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class OfferBookChartViewModel extends ActivatableViewModel {
|
||||
@ -402,7 +400,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
|
||||
for (Offer offer : sortedList) {
|
||||
Price price = offer.getPrice();
|
||||
if (price != null) {
|
||||
double amount = (double) offer.getAmount().value / LongMath.pow(10, offer.getAmount().smallestUnitExponent());
|
||||
double amount = (double) offer.getAmount().longValueExact() / LongMath.pow(10, HavenoUtils.XMR_SMALLEST_UNIT_EXPONENT);
|
||||
accumulatedAmount += amount;
|
||||
offerTableListTemp.add(new OfferListItem(offer, accumulatedAmount));
|
||||
|
||||
|
@ -19,11 +19,11 @@ package bisq.desktop.main.market.spread;
|
||||
|
||||
import bisq.core.monetary.Price;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SpreadItem {
|
||||
@ -36,10 +36,10 @@ public class SpreadItem {
|
||||
public final Price priceSpread;
|
||||
public final String percentage;
|
||||
public final double percentageValue;
|
||||
public final Coin totalAmount;
|
||||
public final BigInteger totalAmount;
|
||||
|
||||
public SpreadItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers,
|
||||
@Nullable Price priceSpread, String percentage, double percentageValue, Coin totalAmount) {
|
||||
@Nullable Price priceSpread, String percentage, double percentageValue, BigInteger totalAmount) {
|
||||
this.currencyCode = currencyCode;
|
||||
this.numberOfBuyOffers = numberOfBuyOffers;
|
||||
this.numberOfSellOffers = numberOfSellOffers;
|
||||
|
@ -26,11 +26,10 @@ import bisq.desktop.util.GUIUtil;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@ -48,6 +47,7 @@ import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Comparator;
|
||||
|
||||
@FxmlView
|
||||
@ -127,7 +127,10 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
|
||||
int numberOfOffers = sortedList.stream().mapToInt(item -> item.numberOfOffers).sum();
|
||||
int numberOfBuyOffers = sortedList.stream().mapToInt(item -> item.numberOfBuyOffers).sum();
|
||||
int numberOfSellOffers = sortedList.stream().mapToInt(item -> item.numberOfSellOffers).sum();
|
||||
String total = formatter.formatCoin(Coin.valueOf(sortedList.stream().mapToLong(item -> item.totalAmount.value).sum()));
|
||||
|
||||
BigInteger totalAmount = BigInteger.valueOf(0);
|
||||
for (SpreadItem item : sortedList) totalAmount = totalAmount.add(item.totalAmount);
|
||||
String total = HavenoUtils.formatToXmr(totalAmount);
|
||||
|
||||
UserThread.execute(() -> {
|
||||
numberOfOffersColumn.setGraphic(new AutoTooltipLabel(Res.get("market.spread.numberOfOffersColumn", numberOfOffers)));
|
||||
|
@ -30,10 +30,10 @@ import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.provider.price.MarketPrice;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@ -48,6 +48,7 @@ import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -135,7 +136,7 @@ class SpreadViewModel extends ActivatableViewModel {
|
||||
}
|
||||
spreadItems.clear();
|
||||
|
||||
Coin totalAmount = null;
|
||||
BigInteger totalAmount = BigInteger.valueOf(0);
|
||||
|
||||
for (String key : offersByCurrencyMap.keySet()) {
|
||||
List<Offer> offers = offersByCurrencyMap.get(key);
|
||||
@ -235,7 +236,7 @@ class SpreadViewModel extends ActivatableViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
totalAmount = Coin.valueOf(offers.stream().mapToLong(offer -> offer.getAmount().getValue()).sum());
|
||||
for (Offer offer : offers) totalAmount = totalAmount.add(offer.getAmount());
|
||||
spreadItems.add(new SpreadItem(key, buyOffers.size(), sellOffers.size(),
|
||||
uniqueOffers.size(), spread, percentage, percentageValue, totalAmount));
|
||||
}
|
||||
@ -243,11 +244,11 @@ class SpreadViewModel extends ActivatableViewModel {
|
||||
maxPlacesForAmount.set(formatAmount(totalAmount, false).length());
|
||||
}
|
||||
|
||||
public String getAmount(Coin amount) {
|
||||
public String getAmount(BigInteger amount) {
|
||||
return formatAmount(amount, true);
|
||||
}
|
||||
|
||||
private String formatAmount(Coin amount, boolean decimalAligned) {
|
||||
return formatter.formatCoin(amount, GUIUtil.AMOUNT_DECIMALS, decimalAligned, maxPlacesForAmount.get());
|
||||
private String formatAmount(BigInteger amount, boolean decimalAligned) {
|
||||
return formatter.formatCoin(HavenoUtils.atomicUnitsToCoin(amount), GUIUtil.AMOUNT_DECIMALS, decimalAligned, maxPlacesForAmount.get());
|
||||
}
|
||||
}
|
||||
|
@ -113,27 +113,26 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
protected TradeCurrency tradeCurrency;
|
||||
protected final StringProperty tradeCurrencyCode = new SimpleStringProperty();
|
||||
protected final BooleanProperty useMarketBasedPrice = new SimpleBooleanProperty();
|
||||
protected final ObjectProperty<Coin> amount = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<Coin> minAmount = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<BigInteger> amount = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<BigInteger> minAmount = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<Price> price = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<Volume> volume = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<Volume> minVolume = new SimpleObjectProperty<>();
|
||||
|
||||
// Percentage value of buyer security deposit. E.g. 0.01 means 1% of trade amount
|
||||
protected final DoubleProperty buyerSecurityDeposit = new SimpleDoubleProperty();
|
||||
protected final DoubleProperty buyerSecurityDepositPct = new SimpleDoubleProperty();
|
||||
|
||||
protected final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
|
||||
|
||||
protected PaymentAccount paymentAccount;
|
||||
boolean isTabSelected;
|
||||
protected double marketPriceMargin = 0;
|
||||
private Coin txFeeFromFeeService = Coin.ZERO;
|
||||
@Getter
|
||||
private boolean marketPriceAvailable;
|
||||
protected boolean allowAmountUpdate = true;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
|
||||
private final Predicate<ObjectProperty<Coin>> isNonZeroAmount = (c) -> c.get() != null && !c.get().isZero();
|
||||
private final Predicate<ObjectProperty<BigInteger>> isNonZeroAmount = (c) -> c.get() != null && c.get().compareTo(BigInteger.valueOf(0)) != 0;
|
||||
private final Predicate<ObjectProperty<Price>> isNonZeroPrice = (p) -> p.get() != null && !p.get().isZero();
|
||||
private final Predicate<ObjectProperty<Volume>> isNonZeroVolume = (v) -> v.get() != null && !v.get().isZero();
|
||||
@Getter
|
||||
@ -176,7 +175,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
addressEntry = xmrWalletService.getOrCreateAddressEntry(offerId, XmrAddressEntry.Context.OFFER_FUNDING);
|
||||
|
||||
useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice());
|
||||
buyerSecurityDeposit.set(Restrictions.getMinBuyerSecurityDepositAsPercent());
|
||||
buyerSecurityDepositPct.set(Restrictions.getMinBuyerSecurityDepositAsPercent());
|
||||
|
||||
xmrBalanceListener = new XmrBalanceListener(getAddressEntry().getSubaddressIndex()) {
|
||||
@Override
|
||||
@ -295,10 +294,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
amount.get(),
|
||||
minAmount.get(),
|
||||
price.get(),
|
||||
txFeeFromFeeService,
|
||||
Coin.ZERO,
|
||||
useMarketBasedPrice.get(),
|
||||
marketPriceMargin,
|
||||
buyerSecurityDeposit.get(),
|
||||
buyerSecurityDepositPct.get(),
|
||||
paymentAccount);
|
||||
}
|
||||
|
||||
@ -319,7 +318,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
setSuggestedSecurityDeposit(getPaymentAccount());
|
||||
|
||||
if (amount.get() != null && this.allowAmountUpdate)
|
||||
this.amount.set(Coin.valueOf(Math.min(amount.get().value, getMaxTradeLimit())));
|
||||
this.amount.set(amount.get().min(BigInteger.valueOf(getMaxTradeLimit())));
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,10 +355,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
// Suggested deposit is double the trade range over the previous lock time period, bounded by min/max deposit
|
||||
var suggestedSecurityDeposit =
|
||||
Math.min(2 * (max - min) / max, Restrictions.getMaxBuyerSecurityDepositAsPercent());
|
||||
buyerSecurityDeposit.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit));
|
||||
buyerSecurityDepositPct.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit));
|
||||
} catch (Throwable t) {
|
||||
log.error(t.toString());
|
||||
buyerSecurityDeposit.set(minSecurityDeposit);
|
||||
buyerSecurityDepositPct.set(minSecurityDeposit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,7 +420,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
boolean isMinAmountLessOrEqualAmount() {
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (minAmount.get() != null && amount.get() != null)
|
||||
return !minAmount.get().isGreaterThan(amount.get());
|
||||
return minAmount.get().compareTo(amount.get()) <= 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -512,7 +511,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
}
|
||||
}
|
||||
|
||||
private Volume calculateVolumeForAmount(ObjectProperty<Coin> minAmount) {
|
||||
private Volume calculateVolumeForAmount(ObjectProperty<BigInteger> minAmount) {
|
||||
Volume volumeByAmount = price.get().getVolumeByAmount(minAmount.get());
|
||||
|
||||
// For HalCash we want multiple of 10 EUR
|
||||
@ -526,7 +525,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
void calculateAmount() {
|
||||
if (isNonZeroPrice.test(price) && isNonZeroVolume.test(volume) && allowAmountUpdate) {
|
||||
try {
|
||||
Coin value = DisplayUtils.reduceTo4Decimals(price.get().getAmountByVolume(volume.get()), btcFormatter);
|
||||
BigInteger value = HavenoUtils.coinToAtomicUnits(DisplayUtils.reduceTo4Decimals(HavenoUtils.atomicUnitsToCoin(price.get().getAmountByVolume(volume.get())), btcFormatter));
|
||||
if (isUsingHalCashAccount())
|
||||
value = CoinUtil.getAdjustedAmountForHalCash(value, price.get(), getMaxTradeLimit());
|
||||
else if (CurrencyUtil.isFiatCurrency(tradeCurrencyCode.get()))
|
||||
@ -546,17 +545,17 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
// Maker does not pay the mining fee for the trade txs because the mining fee might be different when maker
|
||||
// created the offer and reserved his funds, so that would not work well with dynamic fees.
|
||||
// The mining fee for the createOfferFee tx is deducted from the createOfferFee and not visible to the trader
|
||||
final Coin makerFee = getMakerFee();
|
||||
final BigInteger makerFee = getMakerFee();
|
||||
if (direction != null && amount.get() != null && makerFee != null) {
|
||||
Coin feeAndSecDeposit = getSecurityDeposit().add(makerFee);
|
||||
Coin total = isBuyOffer() ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get());
|
||||
totalToPayAsCoin.set(total);
|
||||
BigInteger feeAndSecDeposit = getSecurityDeposit().add(makerFee);
|
||||
BigInteger total = isBuyOffer() ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get());
|
||||
totalToPay.set(total);
|
||||
updateBalance();
|
||||
}
|
||||
}
|
||||
|
||||
Coin getSecurityDeposit() {
|
||||
return isBuyOffer() ? getBuyerSecurityDepositAsCoin() : getSellerSecurityDepositAsCoin();
|
||||
BigInteger getSecurityDeposit() {
|
||||
return isBuyOffer() ? getBuyerSecurityDeposit() : getSellerSecurityDeposit();
|
||||
}
|
||||
|
||||
void swapTradeToSavings() {
|
||||
@ -571,7 +570,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
|
||||
protected abstract Set<PaymentAccount> getUserPaymentAccounts();
|
||||
|
||||
protected void setAmount(Coin amount) {
|
||||
protected void setAmount(BigInteger amount) {
|
||||
this.amount.set(amount);
|
||||
}
|
||||
|
||||
@ -584,18 +583,18 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
}
|
||||
|
||||
protected void setBuyerSecurityDeposit(double value) {
|
||||
this.buyerSecurityDeposit.set(value);
|
||||
this.buyerSecurityDepositPct.set(value);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected ReadOnlyObjectProperty<Coin> getAmount() {
|
||||
protected ReadOnlyObjectProperty<BigInteger> getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
protected ReadOnlyObjectProperty<Coin> getMinAmount() {
|
||||
protected ReadOnlyObjectProperty<BigInteger> getMinAmount() {
|
||||
return minAmount;
|
||||
}
|
||||
|
||||
@ -611,7 +610,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
return minVolume;
|
||||
}
|
||||
|
||||
protected void setMinAmount(Coin minAmount) {
|
||||
protected void setMinAmount(BigInteger minAmount) {
|
||||
this.minAmount.set(minAmount);
|
||||
}
|
||||
|
||||
@ -635,46 +634,46 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
return useMarketBasedPrice;
|
||||
}
|
||||
|
||||
ReadOnlyDoubleProperty getBuyerSecurityDeposit() {
|
||||
return buyerSecurityDeposit;
|
||||
ReadOnlyDoubleProperty getBuyerSecurityDepositPct() {
|
||||
return buyerSecurityDepositPct;
|
||||
}
|
||||
|
||||
protected Coin getBuyerSecurityDepositAsCoin() {
|
||||
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(buyerSecurityDeposit.get(), amount.get());
|
||||
return getBoundedBuyerSecurityDepositAsCoin(percentOfAmountAsCoin);
|
||||
protected BigInteger getBuyerSecurityDeposit() {
|
||||
BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(buyerSecurityDepositPct.get(), amount.get());
|
||||
return getBoundedBuyerSecurityDeposit(percentOfAmount);
|
||||
}
|
||||
|
||||
private Coin getSellerSecurityDepositAsCoin() {
|
||||
Coin amountAsCoin = this.amount.get();
|
||||
if (amountAsCoin == null)
|
||||
amountAsCoin = Coin.ZERO;
|
||||
private BigInteger getSellerSecurityDeposit() {
|
||||
BigInteger amount = this.amount.get();
|
||||
if (amount == null)
|
||||
amount = BigInteger.valueOf(0);
|
||||
|
||||
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(
|
||||
createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDeposit.get()), amountAsCoin);
|
||||
return getBoundedSellerSecurityDepositAsCoin(percentOfAmountAsCoin);
|
||||
BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(
|
||||
createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDepositPct.get()), amount);
|
||||
return getBoundedSellerSecurityDeposit(percentOfAmount);
|
||||
}
|
||||
|
||||
protected Coin getBoundedBuyerSecurityDepositAsCoin(Coin value) {
|
||||
protected BigInteger getBoundedBuyerSecurityDeposit(BigInteger value) {
|
||||
// We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the
|
||||
// MinBuyerSecurityDepositAsCoin from Restrictions.
|
||||
return Coin.valueOf(Math.max(Restrictions.getMinBuyerSecurityDepositAsCoin().value, value.value));
|
||||
// MinBuyerSecurityDeposit from Restrictions.
|
||||
return Restrictions.getMinBuyerSecurityDeposit().max(value);
|
||||
}
|
||||
|
||||
private Coin getBoundedSellerSecurityDepositAsCoin(Coin value) {
|
||||
private BigInteger getBoundedSellerSecurityDeposit(BigInteger value) {
|
||||
// We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the
|
||||
// MinSellerSecurityDepositAsCoin from Restrictions.
|
||||
return Coin.valueOf(Math.max(Restrictions.getMinSellerSecurityDepositAsCoin().value, value.value));
|
||||
// MinSellerSecurityDeposit from Restrictions.
|
||||
return Restrictions.getMinSellerSecurityDeposit().max(value);
|
||||
}
|
||||
|
||||
ReadOnlyObjectProperty<Coin> totalToPayAsCoinProperty() {
|
||||
return totalToPayAsCoin;
|
||||
ReadOnlyObjectProperty<BigInteger> totalToPayAsProperty() {
|
||||
return totalToPay;
|
||||
}
|
||||
|
||||
public void setMarketPriceAvailable(boolean marketPriceAvailable) {
|
||||
this.marketPriceAvailable = marketPriceAvailable;
|
||||
}
|
||||
|
||||
public Coin getMakerFee() {
|
||||
public BigInteger getMakerFee() {
|
||||
return HavenoUtils.getMakerFee(amount.get());
|
||||
}
|
||||
|
||||
@ -684,7 +683,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
}
|
||||
|
||||
public boolean isMinBuyerSecurityDeposit() {
|
||||
return !getBuyerSecurityDepositAsCoin().isGreaterThan(Restrictions.getMinBuyerSecurityDepositAsCoin());
|
||||
return getBuyerSecurityDeposit().compareTo(Restrictions.getMinBuyerSecurityDeposit()) <= 0;
|
||||
}
|
||||
|
||||
public void setTriggerPrice(long triggerPrice) {
|
||||
|
@ -48,6 +48,7 @@ import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.payment.FasterPaymentsAccount;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
@ -58,8 +59,6 @@ import bisq.common.util.Tuple2;
|
||||
import bisq.common.util.Tuple3;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import net.glxn.qrgen.QRCode;
|
||||
import net.glxn.qrgen.image.ImageType;
|
||||
|
||||
@ -105,7 +104,7 @@ import javafx.util.StringConverter;
|
||||
import java.net.URI;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -157,7 +156,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
|
||||
buyerSecurityDepositFocusedListener, priceFocusedListener, placeOfferCompletedListener,
|
||||
priceAsPercentageFocusedListener, getShowWalletFundedNotificationListener,
|
||||
isMinBuyerSecurityDepositListener, triggerPriceFocusedListener;
|
||||
private ChangeListener<Coin> missingCoinListener;
|
||||
private ChangeListener<BigInteger> missingCoinListener;
|
||||
private ChangeListener<String> tradeCurrencyCodeListener, errorMessageListener,
|
||||
marketPriceMarginListener, volumeListener, buyerSecurityDepositInBTCListener;
|
||||
private ChangeListener<Number> marketPriceAvailableListener;
|
||||
@ -248,7 +247,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
|
||||
|
||||
onPaymentAccountsComboBoxSelected();
|
||||
|
||||
balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsCoinProperty().get());
|
||||
balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsProperty().get());
|
||||
updatePriceToggle();
|
||||
|
||||
Label popOverLabel = OfferViewUtil.createPopOverLabel(Res.get("createOffer.triggerPrice.tooltip"));
|
||||
@ -331,7 +330,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
|
||||
// called from parent as the view does not get notified when the tab is closed
|
||||
public void onClose() {
|
||||
// we use model.placeOfferCompleted to not react on close which was triggered by a successful placeOffer
|
||||
if (model.getDataModel().getBalance().get().isPositive() && !model.placeOfferCompleted.get()) {
|
||||
if (model.getDataModel().getBalance().get().compareTo(BigInteger.valueOf(0)) > 0 && !model.placeOfferCompleted.get()) {
|
||||
model.getDataModel().swapTradeToSavings();
|
||||
}
|
||||
}
|
||||
@ -411,7 +410,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
|
||||
triggerPriceVBox.setVisible(false);
|
||||
}
|
||||
|
||||
balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsCoinProperty().get());
|
||||
balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsProperty().get());
|
||||
|
||||
// temporarily disabled due to high CPU usage (per issue #4649)
|
||||
// waitingForFundsSpinner.play();
|
||||
@ -550,7 +549,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
|
||||
volumeTextField.textProperty().bindBidirectional(model.volume);
|
||||
volumeTextField.promptTextProperty().bind(model.volumePromptLabel);
|
||||
totalToPayTextField.textProperty().bind(model.totalToPay);
|
||||
addressTextField.amountAsCoinProperty().bind(model.getDataModel().getMissingCoin());
|
||||
addressTextField.amountAsProperty().bind(model.getDataModel().getMissingCoin());
|
||||
buyerSecurityDepositInputTextField.textProperty().bindBidirectional(model.buyerSecurityDeposit);
|
||||
buyerSecurityDepositLabel.textProperty().bind(model.buyerSecurityDepositLabel);
|
||||
tradeFeeInBtcLabel.textProperty().bind(model.tradeFeeInBtcWithFiat);
|
||||
@ -598,7 +597,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
|
||||
volumeTextField.textProperty().unbindBidirectional(model.volume);
|
||||
volumeTextField.promptTextProperty().unbindBidirectional(model.volume);
|
||||
totalToPayTextField.textProperty().unbind();
|
||||
addressTextField.amountAsCoinProperty().unbind();
|
||||
addressTextField.amountAsProperty().unbind();
|
||||
buyerSecurityDepositInputTextField.textProperty().unbindBidirectional(model.buyerSecurityDeposit);
|
||||
buyerSecurityDepositLabel.textProperty().unbind();
|
||||
tradeFeeInBtcLabel.textProperty().unbind();
|
||||
@ -736,7 +735,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
|
||||
if (newValue) {
|
||||
Notification walletFundedNotification = new Notification()
|
||||
.headLine(Res.get("notification.walletUpdate.headline"))
|
||||
.notification(Res.get("notification.walletUpdate.msg", xmrFormatter.formatCoinWithCode(model.getDataModel().getTotalToPayAsCoin().get())))
|
||||
.notification(Res.get("notification.walletUpdate.msg", HavenoUtils.formatToXmrWithCode(model.getDataModel().getTotalToPay().get())))
|
||||
.autoClose();
|
||||
|
||||
walletFundedNotification.show();
|
||||
|
@ -41,7 +41,7 @@ import bisq.core.offer.OfferRestrictions;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.payment.validation.XmrValidator;
|
||||
import bisq.core.payment.validation.FiatVolumeValidator;
|
||||
import bisq.core.payment.validation.SecurityDepositValidator;
|
||||
import bisq.core.provider.price.MarketPrice;
|
||||
@ -84,6 +84,7 @@ import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -92,7 +93,7 @@ import static javafx.beans.binding.Bindings.createStringBinding;
|
||||
|
||||
@Slf4j
|
||||
public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> extends ActivatableWithDataModel<M> {
|
||||
private final BtcValidator btcValidator;
|
||||
private final XmrValidator xmrValidator;
|
||||
protected final SecurityDepositValidator securityDepositValidator;
|
||||
protected final PriceFeedService priceFeedService;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
@ -163,8 +164,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
private ChangeListener<String> volumeStringListener;
|
||||
private ChangeListener<String> securityDepositStringListener;
|
||||
|
||||
private ChangeListener<Coin> amountAsCoinListener;
|
||||
private ChangeListener<Coin> minAmountAsCoinListener;
|
||||
private ChangeListener<BigInteger> amountListener;
|
||||
private ChangeListener<BigInteger> minAmountListener;
|
||||
private ChangeListener<Price> priceListener;
|
||||
private ChangeListener<Volume> volumeListener;
|
||||
private ChangeListener<Number> securityDepositAsDoubleListener;
|
||||
@ -190,7 +191,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
FiatVolumeValidator fiatVolumeValidator,
|
||||
FiatPriceValidator fiatPriceValidator,
|
||||
AltcoinValidator altcoinValidator,
|
||||
BtcValidator btcValidator,
|
||||
XmrValidator btcValidator,
|
||||
SecurityDepositValidator securityDepositValidator,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
@ -203,7 +204,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
this.fiatVolumeValidator = fiatVolumeValidator;
|
||||
this.fiatPriceValidator = fiatPriceValidator;
|
||||
this.altcoinValidator = altcoinValidator;
|
||||
this.btcValidator = btcValidator;
|
||||
this.xmrValidator = btcValidator;
|
||||
this.securityDepositValidator = securityDepositValidator;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
@ -271,10 +272,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
() -> Res.get("createOffer.volume.prompt", dataModel.getTradeCurrencyCode().get()),
|
||||
dataModel.getTradeCurrencyCode()));
|
||||
|
||||
totalToPay.bind(createStringBinding(() -> btcFormatter.formatCoinWithCode(dataModel.totalToPayAsCoinProperty().get()),
|
||||
dataModel.totalToPayAsCoinProperty()));
|
||||
totalToPay.bind(createStringBinding(() -> HavenoUtils.formatToXmrWithCode(dataModel.totalToPayAsProperty().get()),
|
||||
dataModel.totalToPayAsProperty()));
|
||||
|
||||
tradeAmount.bind(createStringBinding(() -> btcFormatter.formatCoinWithCode(dataModel.getAmount().get()),
|
||||
tradeAmount.bind(createStringBinding(() -> HavenoUtils.formatToXmrWithCode(dataModel.getAmount().get()),
|
||||
dataModel.getAmount()));
|
||||
|
||||
tradeCurrencyCode.bind(dataModel.getTradeCurrencyCode());
|
||||
@ -298,7 +299,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
private void createListeners() {
|
||||
amountStringListener = (ov, oldValue, newValue) -> {
|
||||
if (!ignoreAmountStringListener) {
|
||||
if (isBtcInputValid(newValue).isValid) {
|
||||
if (isXmrInputValid(newValue).isValid) {
|
||||
setAmountToModel();
|
||||
dataModel.calculateVolume();
|
||||
dataModel.calculateTotalToPay();
|
||||
@ -308,7 +309,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
}
|
||||
};
|
||||
minAmountStringListener = (ov, oldValue, newValue) -> {
|
||||
if (isBtcInputValid(newValue).isValid)
|
||||
if (isXmrInputValid(newValue).isValid)
|
||||
setMinAmountToModel();
|
||||
updateButtonDisableState();
|
||||
};
|
||||
@ -431,10 +432,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
};
|
||||
|
||||
|
||||
amountAsCoinListener = (ov, oldValue, newValue) -> {
|
||||
amountListener = (ov, oldValue, newValue) -> {
|
||||
if (newValue != null) {
|
||||
amount.set(btcFormatter.formatCoin(newValue));
|
||||
buyerSecurityDepositInBTC.set(btcFormatter.formatCoinWithCode(dataModel.getBuyerSecurityDepositAsCoin()));
|
||||
amount.set(HavenoUtils.formatToXmr(newValue));
|
||||
buyerSecurityDepositInBTC.set(HavenoUtils.formatToXmrWithCode(dataModel.getBuyerSecurityDeposit()));
|
||||
} else {
|
||||
amount.set("");
|
||||
buyerSecurityDepositInBTC.set("");
|
||||
@ -442,9 +443,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
|
||||
applyMakerFee();
|
||||
};
|
||||
minAmountAsCoinListener = (ov, oldValue, newValue) -> {
|
||||
minAmountListener = (ov, oldValue, newValue) -> {
|
||||
if (newValue != null)
|
||||
minAmount.set(btcFormatter.formatCoin(newValue));
|
||||
minAmount.set(HavenoUtils.formatToXmr(newValue));
|
||||
else
|
||||
minAmount.set("");
|
||||
};
|
||||
@ -473,7 +474,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
if (newValue != null) {
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent((double) newValue));
|
||||
if (dataModel.getAmount().get() != null) {
|
||||
buyerSecurityDepositInBTC.set(btcFormatter.formatCoinWithCode(dataModel.getBuyerSecurityDepositAsCoin()));
|
||||
buyerSecurityDepositInBTC.set(HavenoUtils.formatToXmrWithCode(dataModel.getBuyerSecurityDeposit()));
|
||||
}
|
||||
updateBuyerSecurityDeposit();
|
||||
} else {
|
||||
@ -498,13 +499,13 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
tradeFeeCurrencyCode.set(Res.getBaseCurrencyCode());
|
||||
tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly"));
|
||||
|
||||
Coin makerFeeAsCoin = dataModel.getMakerFee();
|
||||
if (makerFeeAsCoin == null) {
|
||||
BigInteger makerFee = dataModel.getMakerFee();
|
||||
if (makerFee == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
isTradeFeeVisible.setValue(true);
|
||||
tradeFee.set(getFormatterForMakerFee().formatCoin(makerFeeAsCoin));
|
||||
tradeFee.set(HavenoUtils.formatToXmr(makerFee));
|
||||
tradeFeeInBtcWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
|
||||
dataModel.getMakerFee(),
|
||||
btcFormatter));
|
||||
@ -529,11 +530,11 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
buyerSecurityDeposit.addListener(securityDepositStringListener);
|
||||
|
||||
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding
|
||||
dataModel.getAmount().addListener(amountAsCoinListener);
|
||||
dataModel.getMinAmount().addListener(minAmountAsCoinListener);
|
||||
dataModel.getAmount().addListener(amountListener);
|
||||
dataModel.getMinAmount().addListener(minAmountListener);
|
||||
dataModel.getPrice().addListener(priceListener);
|
||||
dataModel.getVolume().addListener(volumeListener);
|
||||
dataModel.getBuyerSecurityDeposit().addListener(securityDepositAsDoubleListener);
|
||||
dataModel.getBuyerSecurityDepositPct().addListener(securityDepositAsDoubleListener);
|
||||
|
||||
// dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
|
||||
dataModel.getIsXmrWalletFunded().addListener(isWalletFundedListener);
|
||||
@ -551,11 +552,11 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
buyerSecurityDeposit.removeListener(securityDepositStringListener);
|
||||
|
||||
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding
|
||||
dataModel.getAmount().removeListener(amountAsCoinListener);
|
||||
dataModel.getMinAmount().removeListener(minAmountAsCoinListener);
|
||||
dataModel.getAmount().removeListener(amountListener);
|
||||
dataModel.getMinAmount().removeListener(minAmountListener);
|
||||
dataModel.getPrice().removeListener(priceListener);
|
||||
dataModel.getVolume().removeListener(volumeListener);
|
||||
dataModel.getBuyerSecurityDeposit().removeListener(securityDepositAsDoubleListener);
|
||||
dataModel.getBuyerSecurityDepositPct().removeListener(securityDepositAsDoubleListener);
|
||||
|
||||
//dataModel.feeFromFundingTxProperty.removeListener(feeFromFundingTxListener);
|
||||
dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener);
|
||||
@ -574,9 +575,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
boolean initWithData(OfferDirection direction, TradeCurrency tradeCurrency) {
|
||||
boolean result = dataModel.initWithData(direction, tradeCurrency);
|
||||
if (dataModel.paymentAccount != null)
|
||||
btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(dataModel.getTradeCurrencyCode().get()));
|
||||
btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit()));
|
||||
btcValidator.setMinValue(Restrictions.getMinTradeAmount());
|
||||
xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
|
||||
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
|
||||
xmrValidator.setMinValue(Restrictions.getMinTradeAmount());
|
||||
|
||||
final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY;
|
||||
|
||||
@ -592,7 +593,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
|
||||
securityDepositValidator.setPaymentAccount(dataModel.paymentAccount);
|
||||
validateAndSetBuyerSecurityDepositToModel();
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
|
||||
buyerSecurityDepositLabel.set(getSecurityDepositLabel());
|
||||
|
||||
applyMakerFee();
|
||||
@ -630,10 +631,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||
dataModel.onPaymentAccountSelected(paymentAccount);
|
||||
if (amount.get() != null)
|
||||
amountValidationResult.set(isBtcInputValid(amount.get()));
|
||||
amountValidationResult.set(isXmrInputValid(amount.get()));
|
||||
|
||||
btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(dataModel.getTradeCurrencyCode().get()));
|
||||
btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit()));
|
||||
xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
|
||||
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
|
||||
maybeShowMakeOfferToUnsignedAccountWarning();
|
||||
|
||||
securityDepositValidator.setPaymentAccount(paymentAccount);
|
||||
@ -659,8 +660,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
updateButtonDisableState();
|
||||
} else {
|
||||
new Popup().warning(Res.get("shared.notEnoughFunds",
|
||||
btcFormatter.formatCoinWithCode(dataModel.totalToPayAsCoinProperty().get()),
|
||||
btcFormatter.formatCoinWithCode(dataModel.getTotalBalance())))
|
||||
HavenoUtils.formatToXmrWithCode(dataModel.totalToPayAsProperty().get()),
|
||||
HavenoUtils.formatToXmrWithCode(dataModel.getTotalBalance())))
|
||||
.actionButtonTextWithGoTo("navigation.funds.depositFunds")
|
||||
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
|
||||
.show();
|
||||
@ -675,12 +676,15 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
// On focus out we do validation and apply the data to the model
|
||||
void onFocusOutAmountTextField(boolean oldValue, boolean newValue) {
|
||||
if (oldValue && !newValue) {
|
||||
InputValidator.ValidationResult result = isBtcInputValid(amount.get());
|
||||
System.out.println("Checking if input valid: " + amount.get());
|
||||
InputValidator.ValidationResult result = isXmrInputValid(amount.get());
|
||||
amountValidationResult.set(result);
|
||||
System.out.println("Result is valid: " + result.isValid);
|
||||
System.out.println("Result error: " + result.errorMessage);
|
||||
if (result.isValid) {
|
||||
setAmountToModel();
|
||||
ignoreAmountStringListener = true;
|
||||
amount.set(btcFormatter.formatCoin(dataModel.getAmount().get()));
|
||||
amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
|
||||
ignoreAmountStringListener = false;
|
||||
dataModel.calculateVolume();
|
||||
|
||||
@ -690,12 +694,12 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
amountValidationResult.set(result);
|
||||
|
||||
if (minAmount.get() != null)
|
||||
minAmountValidationResult.set(isBtcInputValid(minAmount.get()));
|
||||
} else if (amount.get() != null && btcValidator.getMaxTradeLimit() != null && btcValidator.getMaxTradeLimit().value == OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value) {
|
||||
amount.set(btcFormatter.formatCoin(btcValidator.getMaxTradeLimit()));
|
||||
minAmountValidationResult.set(isXmrInputValid(minAmount.get()));
|
||||
} else if (amount.get() != null && xmrValidator.getMaxTradeLimit() != null && xmrValidator.getMaxTradeLimit().longValueExact() == OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact()) {
|
||||
amount.set(HavenoUtils.formatToXmr(xmrValidator.getMaxTradeLimit()));
|
||||
boolean isBuy = dataModel.getDirection() == OfferDirection.BUY;
|
||||
new Popup().information(Res.get(isBuy ? "popup.warning.tradeLimitDueAccountAgeRestriction.buyer" : "popup.warning.tradeLimitDueAccountAgeRestriction.seller",
|
||||
btcFormatter.formatCoinWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT),
|
||||
HavenoUtils.formatToXmrWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT),
|
||||
Res.get("offerbook.warning.newVersionAnnouncement")))
|
||||
.width(900)
|
||||
.show();
|
||||
@ -714,11 +718,11 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
|
||||
public void onFocusOutMinAmountTextField(boolean oldValue, boolean newValue) {
|
||||
if (oldValue && !newValue) {
|
||||
InputValidator.ValidationResult result = isBtcInputValid(minAmount.get());
|
||||
InputValidator.ValidationResult result = isXmrInputValid(minAmount.get());
|
||||
minAmountValidationResult.set(result);
|
||||
if (result.isValid) {
|
||||
Coin minAmountAsCoin = dataModel.getMinAmount().get();
|
||||
syncMinAmountWithAmount = minAmountAsCoin != null && minAmountAsCoin.equals(dataModel.getAmount().get());
|
||||
BigInteger minAmount = dataModel.getMinAmount().get();
|
||||
syncMinAmountWithAmount = minAmount != null && minAmount.equals(dataModel.getAmount().get());
|
||||
setMinAmountToModel();
|
||||
|
||||
dataModel.calculateMinVolume();
|
||||
@ -732,14 +736,14 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
updateButtonDisableState();
|
||||
}
|
||||
|
||||
this.minAmount.set(btcFormatter.formatCoin(minAmountAsCoin));
|
||||
this.minAmount.set(HavenoUtils.formatToXmr(minAmount));
|
||||
|
||||
if (!dataModel.isMinAmountLessOrEqualAmount()) {
|
||||
this.amount.set(this.minAmount.get());
|
||||
} else {
|
||||
minAmountValidationResult.set(result);
|
||||
if (this.amount.get() != null)
|
||||
amountValidationResult.set(isBtcInputValid(this.amount.get()));
|
||||
amountValidationResult.set(isXmrInputValid(this.amount.get()));
|
||||
}
|
||||
} else {
|
||||
syncMinAmountWithAmount = true;
|
||||
@ -864,12 +868,12 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
minAmount.set(amount.getValue());
|
||||
} else {
|
||||
if (amount.get() != null)
|
||||
amountValidationResult.set(isBtcInputValid(amount.get()));
|
||||
amountValidationResult.set(isXmrInputValid(amount.get()));
|
||||
|
||||
// We only check minAmountValidationResult if amountValidationResult is valid, otherwise we would get
|
||||
// triggered a close of the popup when the minAmountValidationResult is applied
|
||||
if (amountValidationResult.getValue() != null && amountValidationResult.getValue().isValid && minAmount.get() != null)
|
||||
minAmountValidationResult.set(isBtcInputValid(minAmount.get()));
|
||||
minAmountValidationResult.set(isXmrInputValid(minAmount.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -899,7 +903,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
.onAction(() -> {
|
||||
dataModel.setBuyerSecurityDeposit(defaultSecurityDeposit);
|
||||
ignoreSecurityDepositStringListener = true;
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
|
||||
ignoreSecurityDepositStringListener = false;
|
||||
})
|
||||
.closeButtonText(Res.get("createOffer.useLowerValue"))
|
||||
@ -916,7 +920,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
private void applyBuyerSecurityDepositOnFocusOut() {
|
||||
setBuyerSecurityDepositToModel();
|
||||
ignoreSecurityDepositStringListener = true;
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
|
||||
ignoreSecurityDepositStringListener = false;
|
||||
}
|
||||
|
||||
@ -985,12 +989,12 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
dataModel.getSecurityDeposit(),
|
||||
dataModel.getAmount().get(),
|
||||
btcFormatter,
|
||||
Restrictions.getMinBuyerSecurityDepositAsCoin()
|
||||
Restrictions.getMinBuyerSecurityDeposit()
|
||||
);
|
||||
}
|
||||
|
||||
public String getSecurityDepositWithCode() {
|
||||
return btcFormatter.formatCoinWithCode(dataModel.getSecurityDeposit());
|
||||
return HavenoUtils.formatToXmrWithCode(dataModel.getSecurityDeposit());
|
||||
}
|
||||
|
||||
|
||||
@ -1003,13 +1007,13 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
}
|
||||
|
||||
public String getMakerFeePercentage() {
|
||||
final Coin makerFeeAsCoin = dataModel.getMakerFee();
|
||||
return GUIUtil.getPercentage(makerFeeAsCoin, dataModel.getAmount().get());
|
||||
final BigInteger makerFee = dataModel.getMakerFee();
|
||||
return GUIUtil.getPercentage(makerFee, dataModel.getAmount().get());
|
||||
}
|
||||
|
||||
public String getTotalToPayInfo() {
|
||||
return OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
|
||||
dataModel.totalToPayAsCoin.get(),
|
||||
dataModel.totalToPay.get(),
|
||||
btcFormatter);
|
||||
}
|
||||
|
||||
@ -1083,7 +1087,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
|
||||
private void setAmountToModel() {
|
||||
if (amount.get() != null && !amount.get().isEmpty()) {
|
||||
Coin amount = DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), btcFormatter);
|
||||
BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), btcFormatter));
|
||||
|
||||
long maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
Price price = dataModel.getPrice().get();
|
||||
@ -1107,7 +1111,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
|
||||
private void setMinAmountToModel() {
|
||||
if (minAmount.get() != null && !minAmount.get().isEmpty()) {
|
||||
Coin minAmount = DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), btcFormatter);
|
||||
BigInteger minAmount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), btcFormatter));
|
||||
|
||||
Price price = dataModel.getPrice().get();
|
||||
long maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
@ -1158,7 +1162,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
|
||||
private void validateAndSetBuyerSecurityDepositToModel() {
|
||||
// If the security deposit in the model is not valid percent
|
||||
String value = FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get());
|
||||
String value = FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get());
|
||||
if (!securityDepositValidator.validate(value).isValid) {
|
||||
dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent());
|
||||
}
|
||||
@ -1168,15 +1172,15 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
if (!makeOfferFromUnsignedAccountWarningDisplayed &&
|
||||
dataModel.getDirection() == OfferDirection.SELL &&
|
||||
PaymentMethod.hasChargebackRisk(dataModel.getPaymentAccount().getPaymentMethod(), dataModel.getTradeCurrency().getCode())) {
|
||||
Coin checkAmount = dataModel.getMinAmount().get() == null ? dataModel.getAmount().get() : dataModel.getMinAmount().get();
|
||||
if (checkAmount != null && !checkAmount.isGreaterThan(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT)) {
|
||||
BigInteger checkAmount = dataModel.getMinAmount().get() == null ? dataModel.getAmount().get() : dataModel.getMinAmount().get();
|
||||
if (checkAmount != null && checkAmount.compareTo(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT) <= 0) {
|
||||
makeOfferFromUnsignedAccountWarningDisplayed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InputValidator.ValidationResult isBtcInputValid(String input) {
|
||||
return btcValidator.validate(input);
|
||||
private InputValidator.ValidationResult isXmrInputValid(String input) {
|
||||
return xmrValidator.validate("" + HavenoUtils.atomicUnitsToXmr(HavenoUtils.parseXmr(input)));
|
||||
}
|
||||
|
||||
private InputValidator.ValidationResult isPriceInputValid(String input) {
|
||||
@ -1219,16 +1223,16 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
|
||||
if (dataModel.isMinBuyerSecurityDeposit()) {
|
||||
buyerSecurityDepositLabel.set(Res.get("createOffer.minSecurityDepositUsed"));
|
||||
buyerSecurityDeposit.set(btcFormatter.formatCoin(Restrictions.getMinBuyerSecurityDepositAsCoin()));
|
||||
buyerSecurityDeposit.set(HavenoUtils.formatToXmr(Restrictions.getMinBuyerSecurityDeposit()));
|
||||
} else {
|
||||
buyerSecurityDepositLabel.set(getSecurityDepositLabel());
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
|
||||
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
|
||||
}
|
||||
}
|
||||
|
||||
void updateButtonDisableState() {
|
||||
boolean inputDataValid = isBtcInputValid(amount.get()).isValid &&
|
||||
isBtcInputValid(minAmount.get()).isValid &&
|
||||
boolean inputDataValid = isXmrInputValid(amount.get()).isValid &&
|
||||
isXmrInputValid(minAmount.get()).isValid &&
|
||||
isPriceInputValid(price.get()).isValid &&
|
||||
dataModel.getPrice().get() != null &&
|
||||
dataModel.getPrice().get().getValue() != 0 &&
|
||||
@ -1249,10 +1253,6 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || !dataModel.getIsXmrWalletFunded().get());
|
||||
}
|
||||
|
||||
private CoinFormatter getFormatterForMakerFee() {
|
||||
return btcFormatter;
|
||||
}
|
||||
|
||||
private void updateMarketPriceToManual() {
|
||||
final String currencyCode = dataModel.getTradeCurrencyCode().get();
|
||||
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);
|
||||
|
@ -23,8 +23,6 @@ import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
@ -32,7 +30,7 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import static bisq.core.util.coin.CoinUtil.minCoin;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Domain for that UI element.
|
||||
@ -48,19 +46,19 @@ public abstract class OfferDataModel extends ActivatableDataModel {
|
||||
@Getter
|
||||
protected final BooleanProperty isXmrWalletFunded = new SimpleBooleanProperty();
|
||||
@Getter
|
||||
protected final ObjectProperty<Coin> totalToPayAsCoin = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<BigInteger> totalToPay = new SimpleObjectProperty<>();
|
||||
@Getter
|
||||
protected final ObjectProperty<Coin> balance = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<BigInteger> balance = new SimpleObjectProperty<>();
|
||||
@Getter
|
||||
protected final ObjectProperty<Coin> availableBalance = new SimpleObjectProperty<>();
|
||||
protected final ObjectProperty<BigInteger> availableBalance = new SimpleObjectProperty<>();
|
||||
@Getter
|
||||
protected final ObjectProperty<Coin> missingCoin = new SimpleObjectProperty<>(Coin.ZERO);
|
||||
protected final ObjectProperty<BigInteger> missingCoin = new SimpleObjectProperty<>(BigInteger.valueOf(0));
|
||||
@Getter
|
||||
protected final BooleanProperty showWalletFundedNotification = new SimpleBooleanProperty();
|
||||
@Getter
|
||||
protected Coin totalBalance;
|
||||
protected BigInteger totalBalance;
|
||||
@Getter
|
||||
protected Coin totalAvailableBalance;
|
||||
protected BigInteger totalAvailableBalance;
|
||||
protected XmrAddressEntry addressEntry;
|
||||
protected boolean useSavingsWallet;
|
||||
|
||||
@ -70,37 +68,37 @@ public abstract class OfferDataModel extends ActivatableDataModel {
|
||||
}
|
||||
|
||||
protected void updateBalance() {
|
||||
Coin tradeWalletBalance = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
||||
BigInteger tradeWalletBalance = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
||||
if (useSavingsWallet) {
|
||||
Coin walletBalance = xmrWalletService.getBalance();
|
||||
BigInteger walletBalance = xmrWalletService.getBalance();
|
||||
totalBalance = walletBalance.add(tradeWalletBalance);
|
||||
if (totalToPayAsCoin.get() != null) {
|
||||
balance.set(minCoin(totalToPayAsCoin.get(), totalBalance));
|
||||
if (totalToPay.get() != null) {
|
||||
balance.set(totalToPay.get().min(totalBalance));
|
||||
}
|
||||
} else {
|
||||
balance.set(tradeWalletBalance);
|
||||
}
|
||||
missingCoin.set(offerUtil.getBalanceShortage(totalToPayAsCoin.get(), balance.get()));
|
||||
isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPayAsCoin.get(), balance.get()));
|
||||
if (totalToPayAsCoin.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) {
|
||||
missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), balance.get()));
|
||||
isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), balance.get()));
|
||||
if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) {
|
||||
showWalletFundedNotification.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateAvailableBalance() {
|
||||
Coin tradeWalletBalance = xmrWalletService.getAvailableBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
||||
BigInteger tradeWalletBalance = xmrWalletService.getAvailableBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
||||
if (useSavingsWallet) {
|
||||
Coin walletAvailableBalance = xmrWalletService.getAvailableBalance();
|
||||
BigInteger walletAvailableBalance = xmrWalletService.getAvailableBalance();
|
||||
totalAvailableBalance = walletAvailableBalance.add(tradeWalletBalance);
|
||||
if (totalToPayAsCoin.get() != null) {
|
||||
availableBalance.set(minCoin(totalToPayAsCoin.get(), totalAvailableBalance));
|
||||
if (totalToPay.get() != null) {
|
||||
availableBalance.set(totalToPay.get().min(totalAvailableBalance));
|
||||
}
|
||||
} else {
|
||||
availableBalance.set(tradeWalletBalance);
|
||||
}
|
||||
missingCoin.set(offerUtil.getBalanceShortage(totalToPayAsCoin.get(), availableBalance.get()));
|
||||
isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPayAsCoin.get(), availableBalance.get()));
|
||||
if (totalToPayAsCoin.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) {
|
||||
missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), availableBalance.get()));
|
||||
isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), availableBalance.get()));
|
||||
if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) {
|
||||
showWalletFundedNotification.set(true);
|
||||
}
|
||||
}
|
||||
|
@ -23,19 +23,17 @@ import bisq.desktop.util.GUIUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.common.app.DevEnv;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Optional;
|
||||
|
||||
// Shared utils for ViewModels
|
||||
public class OfferViewModelUtil {
|
||||
public static String getTradeFeeWithFiatEquivalent(OfferUtil offerUtil,
|
||||
Coin tradeFee,
|
||||
BigInteger tradeFee,
|
||||
CoinFormatter formatter) {
|
||||
|
||||
Optional<Volume> optionalBtcFeeInFiat = offerUtil.getFeeInUserFiatCurrency(tradeFee,
|
||||
@ -45,13 +43,13 @@ public class OfferViewModelUtil {
|
||||
}
|
||||
|
||||
public static String getTradeFeeWithFiatEquivalentAndPercentage(OfferUtil offerUtil,
|
||||
Coin tradeFee,
|
||||
Coin tradeAmount,
|
||||
BigInteger tradeFee,
|
||||
BigInteger tradeAmount,
|
||||
CoinFormatter formatter,
|
||||
Coin minTradeFee) {
|
||||
String feeAsBtc = formatter.formatCoinWithCode(tradeFee);
|
||||
BigInteger minTradeFee) {
|
||||
String feeAsBtc = HavenoUtils.formatToXmrWithCode(tradeFee);
|
||||
String percentage;
|
||||
if (!tradeFee.isGreaterThan(minTradeFee)) {
|
||||
if (tradeFee.compareTo(minTradeFee) <= 0) {
|
||||
percentage = Res.get("guiUtil.requiredMinimum")
|
||||
.replace("(", "")
|
||||
.replace(")", "");
|
||||
|
@ -22,7 +22,7 @@ import bisq.desktop.common.model.ViewModel;
|
||||
import bisq.desktop.main.offer.MutableOfferViewModel;
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.payment.validation.XmrValidator;
|
||||
import bisq.core.payment.validation.FiatVolumeValidator;
|
||||
import bisq.core.payment.validation.SecurityDepositValidator;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
@ -42,7 +42,7 @@ class CreateOfferViewModel extends MutableOfferViewModel<CreateOfferDataModel> i
|
||||
FiatVolumeValidator fiatVolumeValidator,
|
||||
FiatPriceValidator fiatPriceValidator,
|
||||
AltcoinValidator altcoinValidator,
|
||||
BtcValidator btcValidator,
|
||||
XmrValidator btcValidator,
|
||||
SecurityDepositValidator securityDepositValidator,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
|
@ -61,6 +61,7 @@ import bisq.core.offer.OfferRestrictions;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
@ -110,6 +111,8 @@ import javafx.collections.ListChangeListener;
|
||||
import javafx.util.Callback;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -299,15 +302,15 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
||||
avatarColumn.setComparator(Comparator.comparing(o -> model.getNumTrades(o.getOffer())));
|
||||
depositColumn.setComparator(Comparator.comparing(item -> {
|
||||
boolean isSellOffer = item.getOffer().getDirection() == OfferDirection.SELL;
|
||||
Coin deposit = isSellOffer ?
|
||||
BigInteger deposit = isSellOffer ?
|
||||
item.getOffer().getBuyerSecurityDeposit() :
|
||||
item.getOffer().getSellerSecurityDeposit();
|
||||
|
||||
double amountValue = item.getOffer().getAmount().getValue();
|
||||
long amountValue = item.getOffer().getAmount().longValueExact();
|
||||
if ((deposit == null || amountValue == 0)) {
|
||||
return 0d;
|
||||
} else {
|
||||
return deposit.getValue() / amountValue;
|
||||
return BigDecimal.valueOf(deposit.longValueExact()).divide(BigDecimal.valueOf(amountValue)).doubleValue();
|
||||
}
|
||||
|
||||
}, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
@ -715,7 +718,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
||||
if (model.isBootstrappedOrShowPopup()) {
|
||||
String key = "RemoveOfferWarning";
|
||||
if (DontShowAgainLookup.showAgain(key)) {
|
||||
String message = offer.getMakerFee().isPositive() ?
|
||||
String message = offer.getMakerFee().compareTo(BigInteger.valueOf(0)) > 0 ?
|
||||
Res.get("popup.warning.removeOffer", model.getMakerFeeAsString(offer)) :
|
||||
Res.get("popup.warning.removeNoFeeOffer");
|
||||
new Popup().warning(message)
|
||||
@ -1034,7 +1037,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
||||
} else {
|
||||
setText("");
|
||||
setGraphic(new ColoredDecimalPlacesWithZerosText(model.formatDepositString(
|
||||
deposit, item.getOffer().getAmount().getValue()),
|
||||
deposit, item.getOffer().getAmount().longValueExact()),
|
||||
GUIUtil.AMOUNT_DECIMALS_WITH_ZEROS));
|
||||
}
|
||||
} else {
|
||||
@ -1186,7 +1189,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
||||
Res.get("offerbook.timeSinceSigning"),
|
||||
Res.get("offerbook.timeSinceSigning.help",
|
||||
SignedWitnessService.SIGNER_AGE_DAYS,
|
||||
formatter.formatCoinWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT))) {
|
||||
HavenoUtils.formatToXmrWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT))) {
|
||||
{
|
||||
setMinWidth(60);
|
||||
setSortable(true);
|
||||
@ -1206,7 +1209,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
||||
if (item != null && !empty) {
|
||||
var witnessAgeData = item.getWitnessAgeData(accountAgeWitnessService, signedWitnessService);
|
||||
var label = witnessAgeData.isSigningRequired()
|
||||
? new AccountStatusTooltipLabel(witnessAgeData, formatter)
|
||||
? new AccountStatusTooltipLabel(witnessAgeData)
|
||||
: new InfoAutoTooltipLabel(witnessAgeData.getDisplayString(), witnessAgeData.getIcon(), ContentDisplay.RIGHT, witnessAgeData.getInfo());
|
||||
setGraphic(label);
|
||||
} else {
|
||||
|
@ -47,6 +47,7 @@ import bisq.core.payment.PaymentAccountUtil;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.user.User;
|
||||
@ -61,8 +62,6 @@ import bisq.network.p2p.P2PService;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
@ -78,6 +77,8 @@ import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import java.util.Comparator;
|
||||
@ -181,7 +182,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
|
||||
|
||||
filterItemsListener = c -> {
|
||||
final Optional<OfferBookListItem> highestAmountOffer = filteredItems.stream()
|
||||
.max(Comparator.comparingLong(o -> o.getOffer().getAmount().getValue()));
|
||||
.max(Comparator.comparingLong(o -> o.getOffer().getAmount().longValueExact()));
|
||||
|
||||
final boolean containsRangeAmount = filteredItems.stream().anyMatch(o -> o.getOffer().isRange());
|
||||
|
||||
@ -196,7 +197,6 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
|
||||
maxPlacesForAmount.set(formatAmount(item.getOffer(), false).length());
|
||||
maxPlacesForVolume.set(formatVolume(item.getOffer(), false).length());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final Optional<OfferBookListItem> highestPriceOffer = filteredItems.stream()
|
||||
@ -627,7 +627,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
|
||||
}
|
||||
|
||||
public String getMakerFeeAsString(Offer offer) {
|
||||
return btcFormatter.formatCoinWithCode(offer.getMakerFee());
|
||||
return HavenoUtils.formatToXmrWithCode(offer.getMakerFee());
|
||||
}
|
||||
|
||||
private static String getDirectionWithCodeDetailed(OfferDirection direction, String currencyCode) {
|
||||
@ -637,9 +637,9 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
|
||||
return (direction == OfferDirection.SELL) ? Res.get("shared.buyingCurrency", currencyCode) : Res.get("shared.sellingCurrency", currencyCode);
|
||||
}
|
||||
|
||||
public String formatDepositString(Coin deposit, long amount) {
|
||||
var percentage = FormattingUtils.formatToRoundedPercentWithSymbol(deposit.getValue() / (double) amount);
|
||||
return btcFormatter.formatCoin(deposit) + " (" + percentage + ")";
|
||||
public String formatDepositString(BigInteger deposit, long amount) {
|
||||
var percentage = FormattingUtils.formatToRoundedPercentWithSymbol(BigDecimal.valueOf(deposit.longValueExact()).divide(BigDecimal.valueOf(amount)).doubleValue());
|
||||
return HavenoUtils.formatToXmr(deposit) + " (" + percentage + ")";
|
||||
}
|
||||
|
||||
PaymentMethod getShowAllEntryForPaymentMethod() {
|
||||
|
@ -26,7 +26,6 @@ import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.btc.listeners.XmrBalanceListener;
|
||||
import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
@ -47,12 +46,9 @@ import bisq.core.trade.handlers.TradeResultHandler;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.user.User;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.CoinUtil;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
@ -94,13 +90,13 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
private final Navigation navigation;
|
||||
private final P2PService p2PService;
|
||||
|
||||
private Coin securityDeposit;
|
||||
private BigInteger securityDeposit;
|
||||
|
||||
private Offer offer;
|
||||
|
||||
// final BooleanProperty isFeeFromFundingTxSufficient = new SimpleBooleanProperty();
|
||||
// final BooleanProperty isMainNet = new SimpleBooleanProperty();
|
||||
private final ObjectProperty<Coin> amount = new SimpleObjectProperty<>();
|
||||
private final ObjectProperty<BigInteger> amount = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<Volume> volume = new SimpleObjectProperty<>();
|
||||
|
||||
private XmrBalanceListener balanceListener;
|
||||
@ -198,7 +194,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()");
|
||||
paymentAccount = getLastSelectedPaymentAccount();
|
||||
|
||||
this.amount.set(Coin.valueOf(Math.min(offer.getAmount().value, getMaxTradeLimit())));
|
||||
this.amount.set(offer.getAmount().min(BigInteger.valueOf(getMaxTradeLimit())));
|
||||
|
||||
securityDeposit = offer.getDirection() == OfferDirection.SELL ?
|
||||
getBuyerSecurityDeposit() :
|
||||
@ -263,7 +259,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||
checkNotNull(getTakerFee(), "takerFee must not be null");
|
||||
|
||||
Coin fundsNeededForTrade = getFundsNeededForTrade();
|
||||
BigInteger fundsNeededForTrade = getFundsNeededForTrade();
|
||||
if (isBuyOffer())
|
||||
fundsNeededForTrade = fundsNeededForTrade.add(amount.get());
|
||||
|
||||
@ -301,7 +297,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
this.paymentAccount = paymentAccount;
|
||||
|
||||
long myLimit = getMaxTradeLimit();
|
||||
this.amount.set(Coin.valueOf(Math.max(offer.getMinAmount().value, Math.min(amount.get().value, myLimit))));
|
||||
this.amount.set(offer.getMinAmount().max(amount.get().min(BigInteger.valueOf(myLimit))));
|
||||
|
||||
preferences.setTakeOfferSelectedPaymentAccountId(paymentAccount.getId());
|
||||
}
|
||||
@ -385,7 +381,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
void calculateVolume() {
|
||||
if (tradePrice != null && offer != null &&
|
||||
amount.get() != null &&
|
||||
!amount.get().isZero()) {
|
||||
amount.get().compareTo(BigInteger.valueOf(0)) != 0) {
|
||||
Volume volumeByAmount = tradePrice.getVolumeByAmount(amount.get());
|
||||
if (offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID))
|
||||
volumeByAmount = VolumeUtil.getAdjustedVolumeForHalCash(volumeByAmount);
|
||||
@ -398,8 +394,8 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
}
|
||||
}
|
||||
|
||||
void applyAmount(Coin amount) {
|
||||
this.amount.set(Coin.valueOf(Math.min(amount.value, getMaxTradeLimit())));
|
||||
void applyAmount(BigInteger amount) {
|
||||
this.amount.set(amount.min(BigInteger.valueOf(getMaxTradeLimit())));
|
||||
|
||||
calculateTotalToPay();
|
||||
}
|
||||
@ -408,15 +404,15 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
// Taker pays 2 times the tx fee because the mining fee might be different when maker created the offer
|
||||
// and reserved his funds, so that would not work well with dynamic fees.
|
||||
// The mining fee for the takeOfferFee tx is deducted from the createOfferFee and not visible to the trader
|
||||
final Coin takerFee = getTakerFee();
|
||||
final BigInteger takerFee = getTakerFee();
|
||||
if (offer != null && amount.get() != null && takerFee != null) {
|
||||
Coin feeAndSecDeposit = securityDeposit.add(takerFee);
|
||||
BigInteger feeAndSecDeposit = securityDeposit.add(takerFee);
|
||||
if (isBuyOffer())
|
||||
totalToPayAsCoin.set(feeAndSecDeposit.add(amount.get()));
|
||||
totalToPay.set(feeAndSecDeposit.add(amount.get()));
|
||||
else
|
||||
totalToPayAsCoin.set(feeAndSecDeposit);
|
||||
totalToPay.set(feeAndSecDeposit);
|
||||
updateAvailableBalance();
|
||||
log.debug("totalToPayAsCoin {}", totalToPayAsCoin.get().toFriendlyString());
|
||||
log.debug("totalToPay {}", totalToPay.get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +429,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Coin getTakerFee() {
|
||||
BigInteger getTakerFee() {
|
||||
return HavenoUtils.getTakerFee(this.amount.get());
|
||||
}
|
||||
|
||||
@ -450,33 +446,22 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
boolean isMinAmountLessOrEqualAmount() {
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (offer != null && amount.get() != null)
|
||||
return !offer.getMinAmount().isGreaterThan(amount.get());
|
||||
return offer.getMinAmount().compareTo(amount.get()) <= 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean isAmountLargerThanOfferAmount() {
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (amount.get() != null && offer != null)
|
||||
return amount.get().isGreaterThan(offer.getAmount());
|
||||
return amount.get().compareTo(offer.getAmount()) > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean wouldCreateDustForMaker() {
|
||||
//noinspection SimplifiableIfStatement
|
||||
boolean result;
|
||||
if (amount.get() != null && offer != null) {
|
||||
Coin customAmount = offer.getAmount().subtract(amount.get());
|
||||
result = customAmount.isPositive() && customAmount.isLessThan(Restrictions.getMinNonDustOutput());
|
||||
|
||||
if (result)
|
||||
log.info("would create dust for maker, customAmount={}, Restrictions.getMinNonDustOutput()={}", customAmount, Restrictions.getMinNonDustOutput());
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
return false; // TODO: update for XMR?
|
||||
}
|
||||
|
||||
ReadOnlyObjectProperty<Coin> getAmount() {
|
||||
ReadOnlyObjectProperty<BigInteger> getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
@ -493,7 +478,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Coin getFundsNeededForTrade() {
|
||||
private BigInteger getFundsNeededForTrade() {
|
||||
return getSecurityDeposit();
|
||||
}
|
||||
|
||||
@ -501,15 +486,15 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
return addressEntry;
|
||||
}
|
||||
|
||||
public Coin getSecurityDeposit() {
|
||||
public BigInteger getSecurityDeposit() {
|
||||
return securityDeposit;
|
||||
}
|
||||
|
||||
public Coin getBuyerSecurityDeposit() {
|
||||
public BigInteger getBuyerSecurityDeposit() {
|
||||
return offer.getBuyerSecurityDeposit();
|
||||
}
|
||||
|
||||
public Coin getSellerSecurityDeposit() {
|
||||
public BigInteger getSellerSecurityDeposit() {
|
||||
return offer.getSellerSecurityDeposit();
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@ import bisq.core.offer.Offer;
|
||||
import bisq.core.payment.FasterPaymentsAccount;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
@ -65,8 +66,6 @@ import bisq.common.util.Tuple3;
|
||||
import bisq.common.util.Tuple4;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import net.glxn.qrgen.QRCode;
|
||||
import net.glxn.qrgen.image.ImageType;
|
||||
|
||||
@ -108,6 +107,7 @@ import javafx.beans.value.ChangeListener;
|
||||
import java.net.URI;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -208,7 +208,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
if (newValue) {
|
||||
Notification walletFundedNotification = new Notification()
|
||||
.headLine(Res.get("notification.walletUpdate.headline"))
|
||||
.notification(Res.get("notification.walletUpdate.msg", formatter.formatCoinWithCode(model.dataModel.getTotalToPayAsCoin().get())))
|
||||
.notification(Res.get("notification.walletUpdate.msg", HavenoUtils.formatToXmrWithCode(model.dataModel.getTotalToPay().get())))
|
||||
.autoClose();
|
||||
|
||||
walletFundedNotification.show();
|
||||
@ -262,7 +262,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
model.onPaymentAccountSelected(lastPaymentAccount);
|
||||
}
|
||||
|
||||
balanceTextField.setTargetAmount(model.dataModel.getTotalToPayAsCoin().get());
|
||||
balanceTextField.setTargetAmount(model.dataModel.getTotalToPay().get());
|
||||
|
||||
maybeShowTakeOfferFromUnsignedAccountWarning(model.dataModel.getOffer());
|
||||
maybeShowClearXchangeWarning(lastPaymentAccount);
|
||||
@ -359,8 +359,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
|
||||
// Called from parent as the view does not get notified when the tab is closed
|
||||
public void onClose() {
|
||||
Coin availableBalance = model.dataModel.getAvailableBalance().get();
|
||||
if (availableBalance != null && availableBalance.isPositive() && !model.takeOfferCompleted.get() && !DevEnv.isDevMode()) {
|
||||
BigInteger availableBalance = model.dataModel.getAvailableBalance().get();
|
||||
if (availableBalance != null && availableBalance.compareTo(BigInteger.valueOf(0)) > 0 && !model.takeOfferCompleted.get() && !DevEnv.isDevMode()) {
|
||||
model.dataModel.swapTradeToSavings();
|
||||
}
|
||||
}
|
||||
@ -445,7 +445,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
|
||||
updateOfferElementsStyle();
|
||||
|
||||
balanceTextField.setTargetAmount(model.dataModel.getTotalToPayAsCoin().get());
|
||||
balanceTextField.setTargetAmount(model.dataModel.getTotalToPay().get());
|
||||
|
||||
if (!DevEnv.isDevMode()) {
|
||||
String tradeAmountText = model.isSeller() ? Res.get("takeOffer.takeOfferFundWalletInfo.tradeAmount", model.getTradeAmount()) : "";
|
||||
@ -481,7 +481,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
if (walletFundedNotification == null) {
|
||||
walletFundedNotification = new Notification()
|
||||
.headLine(Res.get("notification.walletUpdate.headline"))
|
||||
.notification(Res.get("notification.takeOffer.walletUpdate.msg", formatter.formatCoinWithCode(model.dataModel.getTotalToPayAsCoin().get())))
|
||||
.notification(Res.get("notification.takeOffer.walletUpdate.msg", HavenoUtils.formatToXmrWithCode(model.dataModel.getTotalToPay().get())))
|
||||
.autoClose();
|
||||
walletFundedNotification.show();
|
||||
}
|
||||
@ -542,7 +542,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
amountTextField.textProperty().bindBidirectional(model.amount);
|
||||
volumeTextField.textProperty().bindBidirectional(model.volume);
|
||||
totalToPayTextField.textProperty().bind(model.totalToPay);
|
||||
addressTextField.amountAsCoinProperty().bind(model.dataModel.getMissingCoin());
|
||||
addressTextField.amountAsProperty().bind(model.dataModel.getMissingCoin());
|
||||
amountTextField.validationResultProperty().bind(model.amountValidationResult);
|
||||
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> CurrencyUtil.getCounterCurrency(model.dataModel.getCurrencyCode())));
|
||||
priceAsPercentageLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty());
|
||||
@ -566,7 +566,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
amountTextField.textProperty().unbindBidirectional(model.amount);
|
||||
volumeTextField.textProperty().unbindBidirectional(model.volume);
|
||||
totalToPayTextField.textProperty().unbind();
|
||||
addressTextField.amountAsCoinProperty().unbind();
|
||||
addressTextField.amountAsProperty().unbind();
|
||||
amountTextField.validationResultProperty().unbind();
|
||||
priceCurrencyLabel.textProperty().unbind();
|
||||
priceAsPercentageLabel.prefWidthProperty().unbind();
|
||||
|
@ -37,7 +37,7 @@ import bisq.core.offer.OfferRestrictions;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.payment.validation.XmrValidator;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
@ -52,8 +52,6 @@ import bisq.network.p2p.network.Connection;
|
||||
import bisq.network.p2p.network.ConnectionListener;
|
||||
import bisq.common.UserThread;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@ -78,10 +76,12 @@ import javax.annotation.Nullable;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static javafx.beans.binding.Bindings.createStringBinding;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> implements ViewModel {
|
||||
final TakeOfferDataModel dataModel;
|
||||
private final OfferUtil offerUtil;
|
||||
private final BtcValidator btcValidator;
|
||||
private final XmrValidator btcValidator;
|
||||
private final P2PService p2PService;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final Navigation navigation;
|
||||
@ -118,8 +118,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
|
||||
final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>();
|
||||
|
||||
private ChangeListener<String> amountListener;
|
||||
private ChangeListener<Coin> amountAsCoinListener;
|
||||
private ChangeListener<String> amountStrListener;
|
||||
private ChangeListener<BigInteger> amountListener;
|
||||
private ChangeListener<Boolean> isWalletFundedListener;
|
||||
private ChangeListener<Trade.State> tradeStateListener;
|
||||
private ChangeListener<Offer.State> offerStateListener;
|
||||
@ -136,7 +136,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
@Inject
|
||||
public TakeOfferViewModel(TakeOfferDataModel dataModel,
|
||||
OfferUtil offerUtil,
|
||||
BtcValidator btcValidator,
|
||||
XmrValidator btcValidator,
|
||||
P2PService p2PService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
Navigation navigation,
|
||||
@ -168,7 +168,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
volumeDescriptionLabel.set(Res.get(sellVolumeDescriptionKey, dataModel.getCurrencyCode()));
|
||||
}
|
||||
|
||||
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get()));
|
||||
amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
|
||||
showTransactionPublishedScreen.set(false);
|
||||
|
||||
// when getting back to an open screen we want to re-check again
|
||||
@ -209,7 +209,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
? Res.get(buyAmountDescriptionKey)
|
||||
: Res.get(sellAmountDescriptionKey);
|
||||
|
||||
amountRange = xmrFormatter.formatCoin(offer.getMinAmount()) + " - " + xmrFormatter.formatCoin(offer.getAmount());
|
||||
amountRange = HavenoUtils.formatToXmr(offer.getMinAmount()) + " - " + HavenoUtils.formatToXmr(offer.getAmount());
|
||||
price = FormattingUtils.formatPrice(dataModel.tradePrice);
|
||||
marketPriceMargin = FormattingUtils.formatToPercent(offer.getMarketPriceMarginPct());
|
||||
paymentLabel = Res.get("takeOffer.fundsBox.paymentLabel", offer.getShortId());
|
||||
@ -219,7 +219,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
errorMessage.set(offer.getErrorMessage());
|
||||
|
||||
btcValidator.setMaxValue(offer.getAmount());
|
||||
btcValidator.setMaxTradeLimit(Coin.valueOf(Math.min(dataModel.getMaxTradeLimit(), offer.getAmount().value)));
|
||||
btcValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()).min(offer.getAmount()));
|
||||
btcValidator.setMinValue(offer.getMinAmount());
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
|
||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||
dataModel.onPaymentAccountSelected(paymentAccount);
|
||||
btcValidator.setMaxTradeLimit(Coin.valueOf(Math.min(dataModel.getMaxTradeLimit(), offer.getAmount().value)));
|
||||
btcValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()).min(offer.getAmount()));
|
||||
updateButtonDisableState();
|
||||
}
|
||||
|
||||
@ -265,8 +265,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
return true;
|
||||
} else {
|
||||
new Popup().warning(Res.get("shared.notEnoughFunds",
|
||||
xmrFormatter.formatCoinWithCode(dataModel.getTotalToPayAsCoin().get()),
|
||||
xmrFormatter.formatCoinWithCode(dataModel.getTotalAvailableBalance())))
|
||||
HavenoUtils.formatToXmrWithCode(dataModel.getTotalToPay().get()),
|
||||
HavenoUtils.formatToXmrWithCode(dataModel.getTotalAvailableBalance())))
|
||||
.actionButtonTextWithGoTo("navigation.funds.depositFunds")
|
||||
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
|
||||
.show();
|
||||
@ -276,13 +276,13 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
|
||||
private void applyTakerFee() {
|
||||
tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly"));
|
||||
Coin takerFeeAsCoin = dataModel.getTakerFee();
|
||||
if (takerFeeAsCoin == null) {
|
||||
BigInteger takerFee = dataModel.getTakerFee();
|
||||
if (takerFee == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
isTradeFeeVisible.setValue(true);
|
||||
tradeFee.set(getFormatterForTakerFee().formatCoin(takerFeeAsCoin));
|
||||
tradeFee.set(HavenoUtils.formatToXmr(takerFee));
|
||||
tradeFeeInXmrWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
|
||||
dataModel.getTakerFee(),
|
||||
xmrFormatter));
|
||||
@ -303,27 +303,27 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
// only allow max 4 decimal places for btc values
|
||||
setAmountToModel();
|
||||
// reformat input
|
||||
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get()));
|
||||
amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
|
||||
|
||||
calculateVolume();
|
||||
|
||||
Price tradePrice = dataModel.tradePrice;
|
||||
long maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
if (dataModel.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) {
|
||||
Coin adjustedAmountForHalCash = CoinUtil.getAdjustedAmountForHalCash(dataModel.getAmount().get(),
|
||||
BigInteger adjustedAmountForHalCash = CoinUtil.getAdjustedAmountForHalCash(dataModel.getAmount().get(),
|
||||
tradePrice,
|
||||
maxTradeLimit);
|
||||
dataModel.applyAmount(adjustedAmountForHalCash);
|
||||
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get()));
|
||||
amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
|
||||
} else if (dataModel.getOffer().isFiatOffer()) {
|
||||
if (!isAmountEqualMinAmount(dataModel.getAmount().get()) && (!isAmountEqualMaxAmount(dataModel.getAmount().get()))) {
|
||||
// We only apply the rounding if the amount is variable (minAmount is lower as amount).
|
||||
// Otherwise we could get an amount lower then the minAmount set by rounding
|
||||
Coin roundedAmount = CoinUtil.getRoundedFiatAmount(dataModel.getAmount().get(), tradePrice,
|
||||
BigInteger roundedAmount = CoinUtil.getRoundedFiatAmount(dataModel.getAmount().get(), tradePrice,
|
||||
maxTradeLimit);
|
||||
dataModel.applyAmount(roundedAmount);
|
||||
}
|
||||
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get()));
|
||||
amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
|
||||
}
|
||||
|
||||
if (!dataModel.isMinAmountLessOrEqualAmount())
|
||||
@ -337,16 +337,16 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
if (dataModel.wouldCreateDustForMaker())
|
||||
amountValidationResult.set(new InputValidator.ValidationResult(false,
|
||||
Res.get("takeOffer.validation.amountLargerThanOfferAmountMinusFee")));
|
||||
} else if (btcValidator.getMaxTradeLimit() != null && btcValidator.getMaxTradeLimit().value == OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value) {
|
||||
} else if (btcValidator.getMaxTradeLimit() != null && btcValidator.getMaxTradeLimit().equals(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT)) {
|
||||
if (dataModel.getDirection() == OfferDirection.BUY) {
|
||||
new Popup().information(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.seller",
|
||||
xmrFormatter.formatCoinWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT),
|
||||
HavenoUtils.formatToXmrWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT),
|
||||
Res.get("offerbook.warning.newVersionAnnouncement")))
|
||||
.width(900)
|
||||
.show();
|
||||
} else {
|
||||
new Popup().information(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.buyer",
|
||||
xmrFormatter.formatCoinWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT),
|
||||
HavenoUtils.formatToXmrWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT),
|
||||
Res.get("offerbook.warning.newVersionAnnouncement")))
|
||||
.width(900)
|
||||
.show();
|
||||
@ -468,7 +468,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
|
||||
private void addBindings() {
|
||||
volume.bind(createStringBinding(() -> VolumeUtil.formatVolume(dataModel.volume.get()), dataModel.volume));
|
||||
totalToPay.bind(createStringBinding(() -> xmrFormatter.formatCoinWithCode(dataModel.getTotalToPayAsCoin().get()), dataModel.getTotalToPayAsCoin()));
|
||||
totalToPay.bind(createStringBinding(() -> HavenoUtils.formatToXmrWithCode(dataModel.getTotalToPay().get()), dataModel.getTotalToPay()));
|
||||
}
|
||||
|
||||
|
||||
@ -479,7 +479,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
}
|
||||
|
||||
private void createListeners() {
|
||||
amountListener = (ov, oldValue, newValue) -> {
|
||||
amountStrListener = (ov, oldValue, newValue) -> {
|
||||
if (isBtcInputValid(newValue).isValid) {
|
||||
setAmountToModel();
|
||||
calculateVolume();
|
||||
@ -488,8 +488,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
}
|
||||
updateButtonDisableState();
|
||||
};
|
||||
amountAsCoinListener = (ov, oldValue, newValue) -> {
|
||||
amount.set(xmrFormatter.formatCoin(newValue));
|
||||
amountListener = (ov, oldValue, newValue) -> {
|
||||
amount.set(HavenoUtils.formatToXmr(newValue));
|
||||
applyTakerFee();
|
||||
};
|
||||
isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState();
|
||||
@ -548,10 +548,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
private void addListeners() {
|
||||
// Bidirectional bindings are used for all input fields: amount, price, volume and minAmount
|
||||
// We do volume/amount calculation during input, so user has immediate feedback
|
||||
amount.addListener(amountListener);
|
||||
amount.addListener(amountStrListener);
|
||||
|
||||
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding
|
||||
dataModel.getAmount().addListener(amountAsCoinListener);
|
||||
dataModel.getAmount().addListener(amountListener);
|
||||
|
||||
dataModel.getIsXmrWalletFunded().addListener(isWalletFundedListener);
|
||||
dataModel.getMempoolStatus().addListener(getMempoolStatusListener);
|
||||
@ -563,10 +563,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
amount.removeListener(amountListener);
|
||||
amount.removeListener(amountStrListener);
|
||||
|
||||
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding
|
||||
dataModel.getAmount().removeListener(amountAsCoinListener);
|
||||
dataModel.getAmount().removeListener(amountListener);
|
||||
dataModel.getMempoolStatus().removeListener(getMempoolStatusListener);
|
||||
|
||||
dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener);
|
||||
@ -592,7 +592,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
|
||||
private void setAmountToModel() {
|
||||
if (amount.get() != null && !amount.get().isEmpty()) {
|
||||
Coin amount = DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter);
|
||||
BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter));
|
||||
long maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
Price price = dataModel.tradePrice;
|
||||
if (price != null) {
|
||||
@ -609,12 +609,12 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAmountEqualMinAmount(Coin amount) {
|
||||
return amount.value == offer.getMinAmount().value;
|
||||
private boolean isAmountEqualMinAmount(BigInteger amount) {
|
||||
return offer.getMinAmount().equals(amount);
|
||||
}
|
||||
|
||||
private boolean isAmountEqualMaxAmount(Coin amount) {
|
||||
return amount.value == offer.getAmount().value;
|
||||
private boolean isAmountEqualMaxAmount(BigInteger amount) {
|
||||
return offer.getAmount().equals(amount);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -679,12 +679,12 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
dataModel.getSecurityDeposit(),
|
||||
dataModel.getAmount().get(),
|
||||
xmrFormatter,
|
||||
Restrictions.getMinBuyerSecurityDepositAsCoin()
|
||||
Restrictions.getMinBuyerSecurityDeposit()
|
||||
);
|
||||
}
|
||||
|
||||
public String getSecurityDepositWithCode() {
|
||||
return xmrFormatter.formatCoinWithCode(dataModel.getSecurityDeposit());
|
||||
return HavenoUtils.formatToXmrWithCode(dataModel.getSecurityDeposit());
|
||||
}
|
||||
|
||||
public String getTradeFee() {
|
||||
@ -696,8 +696,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
}
|
||||
|
||||
public String getTakerFeePercentage() {
|
||||
final Coin takerFeeAsCoin = dataModel.getTakerFee();
|
||||
return takerFeeAsCoin != null ? GUIUtil.getPercentage(takerFeeAsCoin, dataModel.getAmount().get()) : Res.get("shared.na");
|
||||
final BigInteger takerFee = dataModel.getTakerFee();
|
||||
return takerFee != null ? GUIUtil.getPercentage(takerFee, dataModel.getAmount().get()) : Res.get("shared.na");
|
||||
}
|
||||
|
||||
public String getTotalToPayInfo() {
|
||||
|
@ -25,10 +25,8 @@ import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.locale.CountryUtil;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.support.dispute.Dispute;
|
||||
import bisq.core.support.dispute.DisputeList;
|
||||
@ -37,19 +35,17 @@ import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import bisq.core.support.dispute.mediation.MediationManager;
|
||||
import bisq.core.support.dispute.refund.RefundManager;
|
||||
import bisq.core.trade.Contract;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
@ -80,7 +76,6 @@ public class ContractWindow extends Overlay<ContractWindow> {
|
||||
private final MediationManager mediationManager;
|
||||
private final RefundManager refundManager;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final CoinFormatter formatter;
|
||||
private Dispute dispute;
|
||||
|
||||
|
||||
@ -92,13 +87,11 @@ public class ContractWindow extends Overlay<ContractWindow> {
|
||||
public ContractWindow(ArbitrationManager arbitrationManager,
|
||||
MediationManager mediationManager,
|
||||
RefundManager refundManager,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
|
||||
AccountAgeWitnessService accountAgeWitnessService) {
|
||||
this.arbitrationManager = arbitrationManager;
|
||||
this.mediationManager = mediationManager;
|
||||
this.refundManager = refundManager;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.formatter = formatter;
|
||||
type = Type.Confirmation;
|
||||
}
|
||||
|
||||
@ -160,18 +153,18 @@ public class ContractWindow extends Overlay<ContractWindow> {
|
||||
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
|
||||
FormattingUtils.formatPrice(contract.getPrice()));
|
||||
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradeAmount"),
|
||||
formatter.formatCoinWithCode(contract.getTradeAmount()));
|
||||
HavenoUtils.formatToXmrWithCode(contract.getTradeAmount()));
|
||||
addConfirmationLabelTextField(gridPane,
|
||||
++rowIndex,
|
||||
VolumeUtil.formatVolumeLabel(currencyCode, ":"),
|
||||
VolumeUtil.formatVolumeWithCode(contract.getTradeVolume()));
|
||||
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) +
|
||||
HavenoUtils.formatToXmrWithCode(offer.getBuyerSecurityDeposit()) +
|
||||
" / " +
|
||||
Res.getWithColAndCap("shared.seller") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit());
|
||||
HavenoUtils.formatToXmrWithCode(offer.getSellerSecurityDeposit());
|
||||
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
|
||||
addConfirmationLabelTextField(gridPane,
|
||||
++rowIndex,
|
||||
|
@ -43,7 +43,6 @@ import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
@ -76,6 +75,7 @@ import javafx.geometry.Insets;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -278,26 +278,26 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
}
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("disputeSummaryWindow.role"), role);
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeAmount"),
|
||||
formatter.formatCoinWithCode(contract.getTradeAmount()));
|
||||
HavenoUtils.formatToXmrWithCode(contract.getTradeAmount()));
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
|
||||
FormattingUtils.formatPrice(contract.getPrice()));
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeVolume"),
|
||||
VolumeUtil.formatVolumeWithCode(contract.getTradeVolume()));
|
||||
String tradeFee = Res.getWithColAndCap("shared.buyer") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(trade.getBuyer() == trade.getMaker() ? trade.getMakerFee() : trade.getTakerFee()) +
|
||||
HavenoUtils.formatToXmrWithCode(trade.getBuyer() == trade.getMaker() ? trade.getMakerFee() : trade.getTakerFee()) +
|
||||
" / " +
|
||||
Res.getWithColAndCap("shared.seller") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(trade.getSeller() == trade.getMaker() ? trade.getMakerFee() : trade.getTakerFee());
|
||||
HavenoUtils.formatToXmrWithCode(trade.getSeller() == trade.getMaker() ? trade.getMakerFee() : trade.getTakerFee());
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeFee"), tradeFee);
|
||||
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(trade.getBuyerSecurityDeposit()) +
|
||||
HavenoUtils.formatToXmrWithCode(trade.getBuyerSecurityDeposit()) +
|
||||
" / " +
|
||||
Res.getWithColAndCap("shared.seller") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(trade.getSellerSecurityDeposit());
|
||||
HavenoUtils.formatToXmrWithCode(trade.getSellerSecurityDeposit());
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
|
||||
}
|
||||
|
||||
@ -356,14 +356,14 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
}
|
||||
|
||||
private boolean isPayoutAmountValid() {
|
||||
Coin buyerAmount = ParsingUtils.parseToCoin(buyerPayoutAmountInputTextField.getText(), formatter);
|
||||
Coin sellerAmount = ParsingUtils.parseToCoin(sellerPayoutAmountInputTextField.getText(), formatter);
|
||||
BigInteger buyerAmount = HavenoUtils.parseXmr(buyerPayoutAmountInputTextField.getText());
|
||||
BigInteger sellerAmount = HavenoUtils.parseXmr(sellerPayoutAmountInputTextField.getText());
|
||||
Contract contract = dispute.getContract();
|
||||
Coin tradeAmount = contract.getTradeAmount();
|
||||
Coin available = tradeAmount
|
||||
BigInteger tradeAmount = contract.getTradeAmount();
|
||||
BigInteger available = tradeAmount
|
||||
.add(trade.getBuyerSecurityDeposit())
|
||||
.add(trade.getSellerSecurityDeposit());
|
||||
Coin totalAmount = buyerAmount.add(sellerAmount);
|
||||
BigInteger totalAmount = buyerAmount.add(sellerAmount);
|
||||
|
||||
boolean isRefundAgent = getDisputeManager(dispute) instanceof RefundManager;
|
||||
if (isRefundAgent) {
|
||||
@ -371,7 +371,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
// be made
|
||||
return totalAmount.compareTo(available) <= 0;
|
||||
} else {
|
||||
if (!totalAmount.isPositive()) {
|
||||
if (totalAmount.compareTo(BigInteger.valueOf(0)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
return totalAmount.compareTo(available) == 0;
|
||||
@ -386,26 +386,26 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
}
|
||||
|
||||
Contract contract = dispute.getContract();
|
||||
Coin available = contract.getTradeAmount()
|
||||
BigInteger available = contract.getTradeAmount()
|
||||
.add(trade.getBuyerSecurityDeposit())
|
||||
.add(trade.getSellerSecurityDeposit());
|
||||
Coin enteredAmount = ParsingUtils.parseToCoin(inputTextField.getText(), formatter);
|
||||
BigInteger enteredAmount = HavenoUtils.parseXmr(inputTextField.getText());
|
||||
if (enteredAmount.compareTo(available) > 0) {
|
||||
enteredAmount = available;
|
||||
Coin finalEnteredAmount = enteredAmount;
|
||||
inputTextField.setText(formatter.formatCoin(finalEnteredAmount));
|
||||
BigInteger finalEnteredAmount = enteredAmount;
|
||||
inputTextField.setText(HavenoUtils.formatToXmr(finalEnteredAmount));
|
||||
}
|
||||
Coin counterPartAsCoin = available.subtract(enteredAmount);
|
||||
String formattedCounterPartAmount = formatter.formatCoin(counterPartAsCoin);
|
||||
Coin buyerAmount;
|
||||
Coin sellerAmount;
|
||||
BigInteger counterPart = available.subtract(enteredAmount);
|
||||
String formattedCounterPartAmount = HavenoUtils.formatToXmr(counterPart);
|
||||
BigInteger buyerAmount;
|
||||
BigInteger sellerAmount;
|
||||
if (inputTextField == buyerPayoutAmountInputTextField) {
|
||||
buyerAmount = enteredAmount;
|
||||
sellerAmount = counterPartAsCoin;
|
||||
sellerAmount = counterPart;
|
||||
sellerPayoutAmountInputTextField.setText(formattedCounterPartAmount);
|
||||
} else {
|
||||
sellerAmount = enteredAmount;
|
||||
buyerAmount = counterPartAsCoin;
|
||||
buyerAmount = counterPart;
|
||||
buyerPayoutAmountInputTextField.setText(formattedCounterPartAmount);
|
||||
}
|
||||
|
||||
@ -619,28 +619,28 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
}
|
||||
|
||||
private void showPayoutTxConfirmation(Contract contract, DisputeResult disputeResult, MoneroTxWallet payoutTx, ResultHandler resultHandler) {
|
||||
Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
String buyerPayoutAddressString = contract.getBuyerPayoutAddressString();
|
||||
Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
String sellerPayoutAddressString = contract.getSellerPayoutAddressString();
|
||||
Coin outputAmount = buyerPayoutAmount.add(sellerPayoutAmount);
|
||||
BigInteger outputAmount = buyerPayoutAmount.add(sellerPayoutAmount);
|
||||
String buyerDetails = "";
|
||||
if (buyerPayoutAmount.isPositive()) {
|
||||
if (buyerPayoutAmount.compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
buyerDetails = Res.get("disputeSummaryWindow.close.txDetails.buyer",
|
||||
formatter.formatCoinWithCode(buyerPayoutAmount),
|
||||
HavenoUtils.formatToXmrWithCode(buyerPayoutAmount),
|
||||
buyerPayoutAddressString);
|
||||
}
|
||||
String sellerDetails = "";
|
||||
if (sellerPayoutAmount.isPositive()) {
|
||||
if (sellerPayoutAmount.compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
sellerDetails = Res.get("disputeSummaryWindow.close.txDetails.seller",
|
||||
formatter.formatCoinWithCode(sellerPayoutAmount),
|
||||
HavenoUtils.formatToXmrWithCode(sellerPayoutAmount),
|
||||
sellerPayoutAddressString);
|
||||
}
|
||||
if (outputAmount.isPositive()) {
|
||||
if (outputAmount.compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
new Popup().width(900)
|
||||
.headLine(Res.get("disputeSummaryWindow.close.txDetails.headline"))
|
||||
.confirmation(Res.get("disputeSummaryWindow.close.txDetails",
|
||||
formatter.formatCoinWithCode(outputAmount),
|
||||
HavenoUtils.formatToXmrWithCode(outputAmount),
|
||||
buyerDetails,
|
||||
sellerDetails,
|
||||
formatter.formatCoinWithCode(HavenoUtils.atomicUnitsToCoin(payoutTx.getFee()))))
|
||||
@ -716,21 +716,21 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
throw new IllegalStateException("Unknown radio button");
|
||||
}
|
||||
disputesService.applyPayoutAmountsToDisputeResult(payout, dispute, disputeResult, -1);
|
||||
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(disputeResult.getBuyerPayoutAmount()));
|
||||
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(disputeResult.getSellerPayoutAmount()));
|
||||
buyerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(disputeResult.getBuyerPayoutAmount()));
|
||||
sellerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(disputeResult.getSellerPayoutAmount()));
|
||||
}
|
||||
|
||||
private void applyTradeAmountRadioButtonStates() {
|
||||
Contract contract = dispute.getContract();
|
||||
Coin buyerSecurityDeposit = trade.getBuyerSecurityDeposit();
|
||||
Coin sellerSecurityDeposit = trade.getSellerSecurityDeposit();
|
||||
Coin tradeAmount = contract.getTradeAmount();
|
||||
BigInteger buyerSecurityDeposit = trade.getBuyerSecurityDeposit();
|
||||
BigInteger sellerSecurityDeposit = trade.getSellerSecurityDeposit();
|
||||
BigInteger tradeAmount = contract.getTradeAmount();
|
||||
|
||||
Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
|
||||
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(buyerPayoutAmount));
|
||||
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(sellerPayoutAmount));
|
||||
buyerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(buyerPayoutAmount));
|
||||
sellerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(sellerPayoutAmount));
|
||||
|
||||
if (buyerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit)) &&
|
||||
sellerPayoutAmount.equals(sellerSecurityDeposit)) {
|
||||
|
@ -32,6 +32,7 @@ import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.Trade.State;
|
||||
@ -44,7 +45,6 @@ import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.util.Tuple2;
|
||||
import bisq.common.util.Tuple4;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.Subscription;
|
||||
|
||||
@ -64,6 +64,7 @@ import javafx.scene.layout.HBox;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -80,7 +81,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
||||
private final KeyRing keyRing;
|
||||
private final Navigation navigation;
|
||||
private Offer offer;
|
||||
private Coin tradeAmount;
|
||||
private BigInteger tradeAmount;
|
||||
private Price tradePrice;
|
||||
private Optional<Runnable> placeOfferHandlerOptional = Optional.empty();
|
||||
private Optional<Runnable> takeOfferHandlerOptional = Optional.empty();
|
||||
@ -106,7 +107,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
||||
type = Type.Confirmation;
|
||||
}
|
||||
|
||||
public void show(Offer offer, Coin tradeAmount, Price tradePrice) {
|
||||
public void show(Offer offer, BigInteger tradeAmount, Price tradePrice) {
|
||||
this.offer = offer;
|
||||
this.tradeAmount = tradeAmount;
|
||||
this.tradePrice = tradePrice;
|
||||
@ -208,14 +209,14 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
||||
String btcAmount = Res.get("shared.btcAmount");
|
||||
if (takeOfferHandlerOptional.isPresent()) {
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo,
|
||||
formatter.formatCoinWithCode(tradeAmount));
|
||||
HavenoUtils.formatToXmrWithCode(tradeAmount));
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + fiatDirectionInfo,
|
||||
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
|
||||
} else {
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo,
|
||||
formatter.formatCoinWithCode(offer.getAmount()));
|
||||
HavenoUtils.formatToXmrWithCode(offer.getAmount()));
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minBtcAmount"),
|
||||
formatter.formatCoinWithCode(offer.getMinAmount()));
|
||||
HavenoUtils.formatToXmrWithCode(offer.getMinAmount()));
|
||||
String volume = VolumeUtil.formatVolumeWithCode(offer.getVolume());
|
||||
String minVolume = "";
|
||||
if (offer.getVolume() != null && offer.getMinVolume() != null &&
|
||||
@ -324,11 +325,11 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
||||
DisplayUtils.formatDateTime(offer.getDate()));
|
||||
String value = Res.getWithColAndCap("shared.buyer") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) +
|
||||
HavenoUtils.formatToXmrWithCode(offer.getBuyerSecurityDeposit()) +
|
||||
" / " +
|
||||
Res.getWithColAndCap("shared.seller") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit());
|
||||
HavenoUtils.formatToXmrWithCode(offer.getSellerSecurityDeposit());
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
|
||||
|
||||
if (countryCode != null && !isF2F)
|
||||
|
@ -31,6 +31,7 @@ import bisq.core.offer.Offer;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import bisq.core.trade.Contract;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.txproof.AssetTxProofResult;
|
||||
@ -162,7 +163,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
||||
}
|
||||
|
||||
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.btcAmount") + btcDirectionInfo,
|
||||
formatter.formatCoinWithCode(trade.getAmount()));
|
||||
HavenoUtils.formatToXmrWithCode(trade.getAmount()));
|
||||
addConfirmationLabelTextField(gridPane, ++rowIndex,
|
||||
VolumeUtil.formatVolumeLabel(offer.getCurrencyCode()) + fiatDirectionInfo,
|
||||
VolumeUtil.formatVolumeWithCode(trade.getVolume()));
|
||||
@ -215,11 +216,11 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
||||
DisplayUtils.formatDateTime(trade.getDate()));
|
||||
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) +
|
||||
HavenoUtils.formatToXmrWithCode(offer.getBuyerSecurityDeposit()) +
|
||||
" / " +
|
||||
Res.getWithColAndCap("shared.seller") +
|
||||
" " +
|
||||
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit());
|
||||
HavenoUtils.formatToXmrWithCode(offer.getSellerSecurityDeposit());
|
||||
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
|
||||
|
||||
NodeAddress arbitratorNodeAddress = trade.getArbitratorNodeAddress();
|
||||
|
@ -29,10 +29,10 @@ import bisq.core.trade.ClosedTradableFormatter;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.Tradable;
|
||||
import bisq.core.trade.Trade;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.Getter;
|
||||
@ -57,7 +57,7 @@ public class ClosedTradesListItem implements FilterableListItem {
|
||||
return tradable.getShortId();
|
||||
}
|
||||
|
||||
public Coin getAmount() {
|
||||
public BigInteger getAmount() {
|
||||
return tradable.getOptionalAmount().orElse(null);
|
||||
}
|
||||
|
||||
|
@ -41,12 +41,11 @@ import bisq.core.util.coin.CoinUtil;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@ -100,7 +99,7 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
|
||||
}
|
||||
|
||||
private double getBuyerSecurityAsPercent(Offer offer) {
|
||||
Coin offerBuyerSecurityDeposit = getBoundedBuyerSecurityDepositAsCoin(offer.getBuyerSecurityDeposit());
|
||||
BigInteger offerBuyerSecurityDeposit = getBoundedBuyerSecurityDeposit(offer.getBuyerSecurityDeposit());
|
||||
double offerBuyerSecurityDepositAsPercent = CoinUtil.getAsPercentPerBtc(offerBuyerSecurityDeposit,
|
||||
offer.getAmount());
|
||||
return Math.min(offerBuyerSecurityDepositAsPercent,
|
||||
|
@ -23,7 +23,7 @@ import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferPayload;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.payment.validation.XmrValidator;
|
||||
import bisq.core.payment.validation.FiatVolumeValidator;
|
||||
import bisq.core.payment.validation.SecurityDepositValidator;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
@ -46,7 +46,7 @@ class DuplicateOfferViewModel extends MutableOfferViewModel<DuplicateOfferDataMo
|
||||
FiatVolumeValidator fiatVolumeValidator,
|
||||
FiatPriceValidator fiatPriceValidator,
|
||||
AltcoinValidator altcoinValidator,
|
||||
BtcValidator btcValidator,
|
||||
XmrValidator btcValidator,
|
||||
SecurityDepositValidator securityDepositValidator,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user