switch to xmr atomic units as native units

This commit is contained in:
woodser 2023-03-05 14:09:14 -05:00
parent ab94b2d6fa
commit 9b4f8046b7
124 changed files with 1155 additions and 1283 deletions

View File

@ -20,6 +20,7 @@ package bisq.core.account.sign;
import bisq.core.account.witness.AccountAgeWitness; import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.filter.FilterManager; import bisq.core.filter.FilterManager;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.trade.HavenoUtils;
import bisq.core.user.User; import bisq.core.user.User;
import bisq.network.p2p.BootstrapListener; import bisq.network.p2p.BootstrapListener;
@ -43,6 +44,7 @@ import javax.inject.Inject;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import java.math.BigInteger;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.SignatureException; import java.security.SignatureException;
@ -68,7 +70,7 @@ import lombok.extern.slf4j.Slf4j;
public class SignedWitnessService { public class SignedWitnessService {
public static final long SIGNER_AGE_DAYS = 30; public static final long SIGNER_AGE_DAYS = 30;
private static final long SIGNER_AGE = SIGNER_AGE_DAYS * ChronoUnit.DAYS.getDuration().toMillis(); 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 KeyRing keyRing;
private final P2PService p2PService; private final P2PService p2PService;
@ -237,7 +239,7 @@ public class SignedWitnessService {
} }
// Arbitrators sign with EC key // Arbitrators sign with EC key
public void signAndPublishAccountAgeWitness(Coin tradeAmount, public void signAndPublishAccountAgeWitness(BigInteger tradeAmount,
AccountAgeWitness accountAgeWitness, AccountAgeWitness accountAgeWitness,
ECKey key, ECKey key,
PublicKey peersPubKey) { PublicKey peersPubKey) {
@ -263,7 +265,7 @@ public class SignedWitnessService {
} }
// Arbitrators sign with EC key // Arbitrators sign with EC key
private String signAndPublishAccountAgeWitness(Coin tradeAmount, private String signAndPublishAccountAgeWitness(BigInteger tradeAmount,
AccountAgeWitness accountAgeWitness, AccountAgeWitness accountAgeWitness,
ECKey key, ECKey key,
byte[] peersPubKey, byte[] peersPubKey,
@ -287,7 +289,7 @@ public class SignedWitnessService {
key.getPubKey(), key.getPubKey(),
peersPubKey, peersPubKey,
time, time,
tradeAmount.value); tradeAmount.longValueExact());
publishSignedWitness(signedWitness); publishSignedWitness(signedWitness);
log.info("Arbitrator signed witness {}", signedWitness.toString()); log.info("Arbitrator signed witness {}", signedWitness.toString());
return ""; return "";
@ -300,7 +302,7 @@ public class SignedWitnessService {
} }
// Any peer can sign with DSA key // Any peer can sign with DSA key
public Optional<SignedWitness> signAndPublishAccountAgeWitness(Coin tradeAmount, public Optional<SignedWitness> signAndPublishAccountAgeWitness(BigInteger tradeAmount,
AccountAgeWitness accountAgeWitness, AccountAgeWitness accountAgeWitness,
PublicKey peersPubKey) throws CryptoException { PublicKey peersPubKey) throws CryptoException {
if (isSignedAccountAgeWitness(accountAgeWitness)) { if (isSignedAccountAgeWitness(accountAgeWitness)) {
@ -320,7 +322,7 @@ public class SignedWitnessService {
keyRing.getSignatureKeyPair().getPublic().getEncoded(), keyRing.getSignatureKeyPair().getPublic().getEncoded(),
peersPubKey.getEncoded(), peersPubKey.getEncoded(),
new Date().getTime(), new Date().getTime(),
tradeAmount.value); tradeAmount.longValueExact());
publishSignedWitness(signedWitness); publishSignedWitness(signedWitness);
log.info("Trader signed witness {}", signedWitness.toString()); log.info("Trader signed witness {}", signedWitness.toString());
return Optional.of(signedWitness); return Optional.of(signedWitness);
@ -438,8 +440,8 @@ public class SignedWitnessService {
return isSignerAccountAgeWitness(accountAgeWitness, new Date().getTime()); return isSignerAccountAgeWitness(accountAgeWitness, new Date().getTime());
} }
public boolean isSufficientTradeAmountForSigning(Coin tradeAmount) { public boolean isSufficientTradeAmountForSigning(BigInteger tradeAmount) {
return !tradeAmount.isLessThan(MINIMUM_TRADE_AMOUNT_FOR_SIGNING); return tradeAmount.compareTo(MINIMUM_TRADE_AMOUNT_FOR_SIGNING) >= 0;
} }
private boolean verifySigner(SignedWitness signedWitness) { private boolean verifySigner(SignedWitness signedWitness) {

View File

@ -53,7 +53,6 @@ import bisq.common.util.MathUtils;
import bisq.common.util.Tuple2; import bisq.common.util.Tuple2;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Utils; import org.bitcoinj.core.Utils;
@ -61,6 +60,7 @@ import javax.inject.Inject;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import java.math.BigInteger;
import java.security.PublicKey; import java.security.PublicKey;
import java.time.Clock; import java.time.Clock;
@ -423,7 +423,7 @@ public class AccountAgeWitnessService {
// Non fiat always has max limit // 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 // Account types that can get signed will use time since signing, other methods use time since account age creation
// when measuring account age // when measuring account age
private long getTradeLimit(Coin maxTradeLimit, private BigInteger getTradeLimit(BigInteger maxTradeLimit,
String currencyCode, String currencyCode,
AccountAgeWitness accountAgeWitness, AccountAgeWitness accountAgeWitness,
AccountAge accountAgeCategory, AccountAge accountAgeCategory,
@ -432,17 +432,17 @@ public class AccountAgeWitnessService {
if (CurrencyUtil.isCryptoCurrency(currencyCode) || if (CurrencyUtil.isCryptoCurrency(currencyCode) ||
!PaymentMethod.hasChargebackRisk(paymentMethod, currencyCode) || !PaymentMethod.hasChargebackRisk(paymentMethod, currencyCode) ||
direction == OfferDirection.SELL) { 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); var factor = signedBuyFactor(accountAgeCategory);
if (factor > 0) { if (factor > 0) {
limit = MathUtils.roundDoubleToLong(maxTradeLimit.value * factor); limit = BigInteger.valueOf(MathUtils.roundDoubleToLong(maxTradeLimit.longValueExact() * factor));
} }
log.debug("limit={}, factor={}, accountAgeWitnessHash={}", log.debug("limit={}, factor={}, accountAgeWitnessHash={}",
Coin.valueOf(limit).toFriendlyString(), limit,
factor, factor,
Utilities.bytesAsHexString(accountAgeWitness.getHash())); Utilities.bytesAsHexString(accountAgeWitness.getHash()));
return limit; return limit;
@ -511,9 +511,9 @@ public class AccountAgeWitnessService {
return 0; return 0;
AccountAgeWitness accountAgeWitness = getMyWitness(paymentAccount.getPaymentAccountPayload()); AccountAgeWitness accountAgeWitness = getMyWitness(paymentAccount.getPaymentAccountPayload());
Coin maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(currencyCode); BigInteger maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimit(currencyCode);
if (hasTradeLimitException(accountAgeWitness)) { if (hasTradeLimitException(accountAgeWitness)) {
return maxTradeLimit.value; return maxTradeLimit.longValueExact();
} }
final long accountSignAge = getWitnessSignAge(accountAgeWitness, new Date()); final long accountSignAge = getWitnessSignAge(accountAgeWitness, new Date());
AccountAge accountAgeCategory = getAccountAgeCategory(accountSignAge); AccountAge accountAgeCategory = getAccountAgeCategory(accountSignAge);
@ -523,7 +523,7 @@ public class AccountAgeWitnessService {
accountAgeWitness, accountAgeWitness,
accountAgeCategory, accountAgeCategory,
direction, direction,
paymentAccount.getPaymentMethod()); paymentAccount.getPaymentMethod()).longValueExact();
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -582,7 +582,7 @@ public class AccountAgeWitnessService {
} }
public boolean verifyPeersTradeAmount(Offer offer, public boolean verifyPeersTradeAmount(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
ErrorMessageHandler errorMessageHandler) { ErrorMessageHandler errorMessageHandler) {
checkNotNull(offer); checkNotNull(offer);
@ -593,8 +593,8 @@ public class AccountAgeWitnessService {
.orElse(isToleratedSmalleAmount(tradeAmount)); .orElse(isToleratedSmalleAmount(tradeAmount));
} }
private boolean isToleratedSmalleAmount(Coin tradeAmount) { private boolean isToleratedSmalleAmount(BigInteger tradeAmount) {
return tradeAmount.value <= OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value; return tradeAmount.longValueExact() <= OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact();
} }
@ -642,14 +642,14 @@ public class AccountAgeWitnessService {
} }
private boolean verifyPeersTradeLimit(Offer offer, private boolean verifyPeersTradeLimit(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
AccountAgeWitness peersWitness, AccountAgeWitness peersWitness,
Date peersCurrentDate, Date peersCurrentDate,
ErrorMessageHandler errorMessageHandler) { ErrorMessageHandler errorMessageHandler) {
checkNotNull(offer); checkNotNull(offer);
final String currencyCode = offer.getCurrencyCode(); final String currencyCode = offer.getCurrencyCode();
final Coin defaultMaxTradeLimit = offer.getPaymentMethod().getMaxTradeLimitAsCoin(currencyCode); final BigInteger defaultMaxTradeLimit = offer.getPaymentMethod().getMaxTradeLimit(currencyCode);
long peersCurrentTradeLimit = defaultMaxTradeLimit.value; BigInteger peersCurrentTradeLimit = defaultMaxTradeLimit;
if (!hasTradeLimitException(peersWitness)) { if (!hasTradeLimitException(peersWitness)) {
final long accountSignAge = getWitnessSignAge(peersWitness, peersCurrentDate); final long accountSignAge = getWitnessSignAge(peersWitness, peersCurrentDate);
AccountAge accountAgeCategory = getPeersAccountAgeCategory(accountSignAge); AccountAge accountAgeCategory = getPeersAccountAgeCategory(accountSignAge);
@ -659,11 +659,11 @@ public class AccountAgeWitnessService {
accountAgeCategory, direction, offer.getPaymentMethod()); accountAgeCategory, direction, offer.getPaymentMethod());
} }
// Makers current trade limit cannot be smaller than that in the offer // 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) { if (!result) {
String msg = "The peers trade limit is less than the traded amount.\n" + String msg = "The peers trade limit is less than the traded amount.\n" +
"tradeAmount=" + tradeAmount.toFriendlyString() + "tradeAmount=" + tradeAmount +
"\nPeers trade limit=" + Coin.valueOf(peersCurrentTradeLimit).toFriendlyString() + "\nPeers trade limit=" + peersCurrentTradeLimit +
"\nOffer ID=" + offer.getShortId() + "\nOffer ID=" + offer.getShortId() +
"\nPaymentMethod=" + offer.getPaymentMethod().getId() + "\nPaymentMethod=" + offer.getPaymentMethod().getId() +
"\nCurrencyCode=" + offer.getCurrencyCode(); "\nCurrencyCode=" + offer.getCurrencyCode();
@ -698,7 +698,7 @@ public class AccountAgeWitnessService {
// Witness signing // Witness signing
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void arbitratorSignAccountAgeWitness(Coin tradeAmount, public void arbitratorSignAccountAgeWitness(BigInteger tradeAmount,
AccountAgeWitness accountAgeWitness, AccountAgeWitness accountAgeWitness,
ECKey key, ECKey key,
PublicKey peersPubKey) { PublicKey peersPubKey) {
@ -737,7 +737,7 @@ public class AccountAgeWitnessService {
public Optional<SignedWitness> traderSignAndPublishPeersAccountAgeWitness(Trade trade) { public Optional<SignedWitness> traderSignAndPublishPeersAccountAgeWitness(Trade trade) {
AccountAgeWitness peersWitness = findTradePeerWitness(trade).orElse(null); AccountAgeWitness peersWitness = findTradePeerWitness(trade).orElse(null);
Coin tradeAmount = trade.getAmount(); BigInteger tradeAmount = trade.getAmount();
checkNotNull(trade.getTradePeer().getPubKeyRing(), "Peer must have a keyring"); checkNotNull(trade.getTradePeer().getPubKeyRing(), "Peer must have a keyring");
PublicKey peersPubKey = trade.getTradePeer().getPubKeyRing().getSignaturePubKey(); PublicKey peersPubKey = trade.getTradePeer().getPubKeyRing().getSignaturePubKey();
checkNotNull(peersWitness, "Not able to find peers witness, unable to sign for trade {}", 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) { private Stream<TraderDataItem> getTraderData(Dispute dispute) {
Coin tradeAmount = dispute.getContract().getTradeAmount(); BigInteger tradeAmount = dispute.getContract().getTradeAmount();
PubKeyRing buyerPubKeyRing = dispute.getContract().getBuyerPubKeyRing(); PubKeyRing buyerPubKeyRing = dispute.getContract().getBuyerPubKeyRing();
PubKeyRing sellerPubKeyRing = dispute.getContract().getSellerPubKeyRing(); PubKeyRing sellerPubKeyRing = dispute.getContract().getSellerPubKeyRing();
@ -841,7 +841,7 @@ public class AccountAgeWitnessService {
return signedWitnessService.isSignerAccountAgeWitness(accountAgeWitness); return signedWitnessService.isSignerAccountAgeWitness(accountAgeWitness);
} }
public boolean tradeAmountIsSufficient(Coin tradeAmount) { public boolean tradeAmountIsSufficient(BigInteger tradeAmount) {
return signedWitnessService.isSufficientTradeAmountForSigning(tradeAmount); return signedWitnessService.isSufficientTradeAmountForSigning(tradeAmount);
} }

View File

@ -48,7 +48,6 @@ import bisq.common.handlers.ResultHandler;
import bisq.proto.grpc.NotificationMessage; import bisq.proto.grpc.NotificationMessage;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import javax.inject.Inject; import javax.inject.Inject;
@ -58,7 +57,7 @@ import com.google.common.util.concurrent.FutureCallback;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -446,8 +445,8 @@ public class CoreApi {
Price price, Price price,
boolean useMarketBasedPrice, boolean useMarketBasedPrice,
double marketPriceMargin, double marketPriceMargin,
Coin amount, BigInteger amount,
Coin minAmount, BigInteger minAmount,
double buyerSecurityDeposit, double buyerSecurityDeposit,
PaymentAccount paymentAccount) { PaymentAccount paymentAccount) {
return coreOffersService.editOffer(offerId, return coreOffersService.editOffer(offerId,
@ -552,10 +551,6 @@ public class CoreApi {
coreTradesService.closeTrade(tradeId); coreTradesService.closeTrade(tradeId);
} }
public void withdrawFunds(String tradeId, String address, String memo) {
coreTradesService.withdrawFunds(tradeId, address, memo);
}
public Trade getTrade(String tradeId) { public Trade getTrade(String tradeId) {
return coreTradesService.getTrade(tradeId); return coreTradesService.getTrade(tradeId);
} }

View File

@ -24,8 +24,6 @@ import bisq.common.crypto.PubKeyRing;
import bisq.common.handlers.FaultHandler; import bisq.common.handlers.FaultHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
import org.bitcoinj.core.Coin;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -40,6 +38,8 @@ import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format; import static java.lang.String.format;
import java.math.BigInteger;
@Singleton @Singleton
@Slf4j @Slf4j
@ -217,33 +217,32 @@ public class CoreDisputesService {
public void applyPayoutAmountsToDisputeResult(DisputePayout payout, Dispute dispute, DisputeResult disputeResult, long customWinnerAmount) { public void applyPayoutAmountsToDisputeResult(DisputePayout payout, Dispute dispute, DisputeResult disputeResult, long customWinnerAmount) {
Contract contract = dispute.getContract(); Contract contract = dispute.getContract();
Trade trade = tradeManager.getTrade(dispute.getTradeId()); Trade trade = tradeManager.getTrade(dispute.getTradeId());
Coin buyerSecurityDeposit = trade.getBuyerSecurityDeposit(); BigInteger buyerSecurityDeposit = trade.getBuyerSecurityDeposit();
Coin sellerSecurityDeposit = trade.getSellerSecurityDeposit(); BigInteger sellerSecurityDeposit = trade.getSellerSecurityDeposit();
Coin tradeAmount = contract.getTradeAmount(); BigInteger tradeAmount = contract.getTradeAmount();
if (payout == DisputePayout.BUYER_GETS_TRADE_AMOUNT) { if (payout == DisputePayout.BUYER_GETS_TRADE_AMOUNT) {
disputeResult.setBuyerPayoutAmount(tradeAmount.add(buyerSecurityDeposit)); disputeResult.setBuyerPayoutAmount(tradeAmount.add(buyerSecurityDeposit));
disputeResult.setSellerPayoutAmount(sellerSecurityDeposit); disputeResult.setSellerPayoutAmount(sellerSecurityDeposit);
} else if (payout == DisputePayout.BUYER_GETS_ALL) { } else if (payout == DisputePayout.BUYER_GETS_ALL) {
disputeResult.setBuyerPayoutAmount(tradeAmount disputeResult.setBuyerPayoutAmount(tradeAmount
.add(buyerSecurityDeposit) .add(buyerSecurityDeposit)
.add(sellerSecurityDeposit)); // TODO (woodser): apply min payout to incentivize loser (see post v1.1.7) .add(sellerSecurityDeposit)); // TODO (woodser): apply min payout to incentivize loser? (see post v1.1.7)
disputeResult.setSellerPayoutAmount(Coin.ZERO); disputeResult.setSellerPayoutAmount(BigInteger.valueOf(0));
} else if (payout == DisputePayout.SELLER_GETS_TRADE_AMOUNT) { } else if (payout == DisputePayout.SELLER_GETS_TRADE_AMOUNT) {
disputeResult.setBuyerPayoutAmount(buyerSecurityDeposit); disputeResult.setBuyerPayoutAmount(buyerSecurityDeposit);
disputeResult.setSellerPayoutAmount(tradeAmount.add(sellerSecurityDeposit)); disputeResult.setSellerPayoutAmount(tradeAmount.add(sellerSecurityDeposit));
} else if (payout == DisputePayout.SELLER_GETS_ALL) { } else if (payout == DisputePayout.SELLER_GETS_ALL) {
disputeResult.setBuyerPayoutAmount(Coin.ZERO); disputeResult.setBuyerPayoutAmount(BigInteger.valueOf(0));
disputeResult.setSellerPayoutAmount(tradeAmount disputeResult.setSellerPayoutAmount(tradeAmount
.add(sellerSecurityDeposit) .add(sellerSecurityDeposit)
.add(buyerSecurityDeposit)); .add(buyerSecurityDeposit));
} else if (payout == DisputePayout.CUSTOM) { } else if (payout == DisputePayout.CUSTOM) {
Coin winnerAmount = Coin.valueOf(customWinnerAmount); if (customWinnerAmount > trade.getWallet().getBalance().longValueExact()) {
if (winnerAmount.compareTo(HavenoUtils.atomicUnitsToCoin(trade.getWallet().getBalance())) > 0) {
throw new RuntimeException("The custom winner payout amount is more than the trade wallet's balance"); 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); long loserAmount = tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit).subtract(BigInteger.valueOf(customWinnerAmount)).longValueExact();
disputeResult.setBuyerPayoutAmount(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? winnerAmount : loserAmount); disputeResult.setBuyerPayoutAmount(BigInteger.valueOf(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? customWinnerAmount : loserAmount));
disputeResult.setSellerPayoutAmount(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? loserAmount : winnerAmount); 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(); String agentNodeAddress = checkNotNull(disputeManager.getAgentNodeAddress(dispute)).getFullAddress();
Contract contract = dispute.getContract(); Contract contract = dispute.getContract();
String currencyCode = contract.getOfferPayload().getCurrencyCode(); String currencyCode = contract.getOfferPayload().getCurrencyCode();
String amount = formatter.formatCoinWithCode(contract.getTradeAmount()); String amount = HavenoUtils.formatToXmrWithCode(contract.getTradeAmount());
String textToSign = Res.get("disputeSummaryWindow.close.msg", String textToSign = Res.get("disputeSummaryWindow.close.msg",
FormattingUtils.formatDateTime(disputeResult.getCloseDate(), true), FormattingUtils.formatDateTime(disputeResult.getCloseDate(), true),
@ -264,8 +263,8 @@ public class CoreDisputesService {
currencyCode, currencyCode,
Res.get("disputeSummaryWindow.reason." + reason.name()), Res.get("disputeSummaryWindow.reason." + reason.name()),
amount, amount,
formatter.formatCoinWithCode(disputeResult.getBuyerPayoutAmount()), HavenoUtils.formatToXmrWithCode(disputeResult.getBuyerPayoutAmount()),
formatter.formatCoinWithCode(disputeResult.getSellerPayoutAmount()), HavenoUtils.formatToXmrWithCode(disputeResult.getSellerPayoutAmount()),
disputeResult.summaryNotesProperty().get() disputeResult.summaryNotesProperty().get()
); );

View File

@ -41,6 +41,7 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
@ -181,8 +182,8 @@ public class CoreOffersService {
String offerId = createOfferService.getRandomOfferId(); String offerId = createOfferService.getRandomOfferId();
OfferDirection direction = OfferDirection.valueOf(directionAsString.toUpperCase()); OfferDirection direction = OfferDirection.valueOf(directionAsString.toUpperCase());
Price price = priceAsString.isEmpty() ? null : Price.valueOf(upperCaseCurrencyCode, priceStringToLong(priceAsString, upperCaseCurrencyCode)); Price price = priceAsString.isEmpty() ? null : Price.valueOf(upperCaseCurrencyCode, priceStringToLong(priceAsString, upperCaseCurrencyCode));
Coin amount = Coin.valueOf(amountAsLong); BigInteger amount = BigInteger.valueOf(amountAsLong);
Coin minAmount = Coin.valueOf(minAmountAsLong); BigInteger minAmount = BigInteger.valueOf(minAmountAsLong);
Coin useDefaultTxFee = Coin.ZERO; Coin useDefaultTxFee = Coin.ZERO;
Offer offer = createOfferService.createAndGetOffer(offerId, Offer offer = createOfferService.createAndGetOffer(offerId,
direction, direction,
@ -214,8 +215,8 @@ public class CoreOffersService {
Price price, Price price,
boolean useMarketBasedPrice, boolean useMarketBasedPrice,
double marketPriceMargin, double marketPriceMargin,
Coin amount, BigInteger amount,
Coin minAmount, BigInteger minAmount,
double buyerSecurityDeposit, double buyerSecurityDeposit,
PaymentAccount paymentAccount) { PaymentAccount paymentAccount) {
Coin useDefaultTxFee = Coin.ZERO; Coin useDefaultTxFee = Coin.ZERO;

View File

@ -25,6 +25,7 @@ import bisq.core.offer.Offer;
import bisq.core.offer.OfferBookService; import bisq.core.offer.OfferBookService;
import bisq.core.offer.OfferDirection; import bisq.core.offer.OfferDirection;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.HavenoUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -111,7 +112,7 @@ class CorePriceService {
for(Offer offer: buyOffers) { for(Offer offer: buyOffers) {
Price price = offer.getPrice(); Price price = offer.getPrice();
if (price != null) { 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; accumulatedAmount += amount;
double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent()); double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent());
buyTM.put(mapPriceFeedServicePrice(priceAsDouble, currencyCode), accumulatedAmount); buyTM.put(mapPriceFeedServicePrice(priceAsDouble, currencyCode), accumulatedAmount);
@ -124,7 +125,7 @@ class CorePriceService {
for(Offer offer: sellOffers){ for(Offer offer: sellOffers){
Price price = offer.getPrice(); Price price = offer.getPrice();
if (price != null) { 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; accumulatedAmount += amount;
double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent()); double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent());
sellTM.put(mapPriceFeedServicePrice(priceAsDouble, currencyCode), accumulatedAmount); sellTM.put(mapPriceFeedServicePrice(priceAsDouble, currencyCode), accumulatedAmount);

View File

@ -50,6 +50,8 @@ import lombok.extern.slf4j.Slf4j;
import static bisq.core.btc.model.AddressEntry.Context.TRADE_PAYOUT; import static bisq.core.btc.model.AddressEntry.Context.TRADE_PAYOUT;
import static java.lang.String.format; import static java.lang.String.format;
import java.math.BigInteger;
@Singleton @Singleton
@Slf4j @Slf4j
class CoreTradesService { class CoreTradesService {
@ -103,8 +105,8 @@ class CoreTradesService {
var useSavingsWallet = true; var useSavingsWallet = true;
// synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model // synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model
Coin takerFee; BigInteger takerFee;
Coin fundsNeededForTrade; BigInteger fundsNeededForTrade;
synchronized (takeOfferModel) { synchronized (takeOfferModel) {
takeOfferModel.initModel(offer, paymentAccount, useSavingsWallet); takeOfferModel.initModel(offer, paymentAccount, useSavingsWallet);
takerFee = takeOfferModel.getTakerFee(); takerFee = takeOfferModel.getTakerFee();
@ -164,47 +166,6 @@ class CoreTradesService {
tradeManager.onTradeCompleted(trade); 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) { String getTradeRole(String tradeId) {
coreWalletsService.verifyWalletsAreAvailable(); coreWalletsService.verifyWalletsAreAvailable();
coreWalletsService.verifyEncryptedWalletIsUnlocked(); coreWalletsService.verifyEncryptedWalletIsUnlocked();

View File

@ -21,7 +21,6 @@ import bisq.core.api.model.builder.OfferInfoBuilder;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OpenOffer; import bisq.core.offer.OpenOffer;
import bisq.core.trade.HavenoUtils;
import bisq.common.Payload; import bisq.common.Payload;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import java.util.Optional; import java.util.Optional;
@ -151,14 +150,14 @@ public class OfferInfo implements Payload {
.withPrice(preciseOfferPrice) .withPrice(preciseOfferPrice)
.withUseMarketBasedPrice(offer.isUseMarketBasedPrice()) .withUseMarketBasedPrice(offer.isUseMarketBasedPrice())
.withMarketPriceMarginPct(marketPriceMarginAsPctLiteral) .withMarketPriceMarginPct(marketPriceMarginAsPctLiteral)
.withAmount(HavenoUtils.centinerosToAtomicUnits(offer.getAmount().value).longValueExact()) .withAmount(offer.getAmount().longValueExact())
.withMinAmount(HavenoUtils.centinerosToAtomicUnits(offer.getMinAmount().value).longValueExact()) .withMinAmount(offer.getMinAmount().longValueExact())
.withVolume(roundedVolume) .withVolume(roundedVolume)
.withMinVolume(roundedMinVolume) .withMinVolume(roundedMinVolume)
.withMakerFee(HavenoUtils.centinerosToAtomicUnits(offer.getMakerFee().value).longValueExact()) .withMakerFee(offer.getMakerFee().longValueExact())
.withOfferFeePaymentTxId(offer.getOfferFeePaymentTxId()) .withOfferFeePaymentTxId(offer.getOfferFeePaymentTxId())
.withBuyerSecurityDeposit(HavenoUtils.centinerosToAtomicUnits(offer.getBuyerSecurityDeposit().value).longValueExact()) .withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().longValueExact())
.withSellerSecurityDeposit(HavenoUtils.centinerosToAtomicUnits(offer.getSellerSecurityDeposit().value).longValueExact()) .withSellerSecurityDeposit(offer.getSellerSecurityDeposit().longValueExact())
.withPaymentAccountId(offer.getMakerPaymentAccountId()) .withPaymentAccountId(offer.getMakerPaymentAccountId())
.withPaymentMethodId(offer.getPaymentMethod().getId()) .withPaymentMethodId(offer.getPaymentMethod().getId())
.withPaymentMethodShortName(offer.getPaymentMethod().getShortName()) .withPaymentMethodShortName(offer.getPaymentMethod().getShortName())

View File

@ -161,8 +161,8 @@ public class TradeInfo implements Payload {
.withTakerDepositTxId(trade.getTaker().getDepositTxHash()) .withTakerDepositTxId(trade.getTaker().getDepositTxHash())
.withPayoutTxId(trade.getPayoutTxId()) .withPayoutTxId(trade.getPayoutTxId())
.withAmountAsLong(trade.getAmountAsLong()) .withAmountAsLong(trade.getAmountAsLong())
.withBuyerSecurityDeposit(trade.getBuyerSecurityDeposit() == null ? -1 : trade.getBuyerSecurityDeposit().value) .withBuyerSecurityDeposit(trade.getBuyerSecurityDeposit() == null ? -1 : trade.getBuyerSecurityDeposit().longValueExact())
.withSellerSecurityDeposit(trade.getSellerSecurityDeposit() == null ? -1 : trade.getSellerSecurityDeposit().value) .withSellerSecurityDeposit(trade.getSellerSecurityDeposit() == null ? -1 : trade.getSellerSecurityDeposit().longValueExact())
.withPrice(toPreciseTradePrice.apply(trade)) .withPrice(toPreciseTradePrice.apply(trade))
.withVolume(toRoundedVolume.apply(trade)) .withVolume(toRoundedVolume.apply(trade))
.withArbitratorNodeAddress(toArbitratorNodeAddress.apply(trade)) .withArbitratorNodeAddress(toArbitratorNodeAddress.apply(trade))

View File

@ -18,18 +18,21 @@
package bisq.core.btc.wallet; package bisq.core.btc.wallet;
import bisq.common.config.Config; import bisq.common.config.Config;
import bisq.core.trade.HavenoUtils;
import java.math.BigInteger;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
public class Restrictions { public class Restrictions {
private static Coin MIN_TRADE_AMOUNT; private static BigInteger MIN_TRADE_AMOUNT;
private static Coin MIN_BUYER_SECURITY_DEPOSIT; 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 // 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. // 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 // 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. // 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() { public static Coin getMinNonDustOutput() {
if (minNonDustOutput == null) if (minNonDustOutput == null)
@ -47,9 +50,9 @@ public class Restrictions {
return !isAboveDust(amount); return !isAboveDust(amount);
} }
public static Coin getMinTradeAmount() { public static BigInteger getMinTradeAmount() {
if (MIN_TRADE_AMOUNT == null) 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; 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. // 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. // 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) 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; return MIN_BUYER_SECURITY_DEPOSIT;
} }
@ -78,16 +81,16 @@ public class Restrictions {
return 0.15; // 15% of trade amount. return 0.15; // 15% of trade amount.
} }
public static Coin getMinSellerSecurityDepositAsCoin() { public static BigInteger getMinSellerSecurityDeposit() {
if (SELLER_SECURITY_DEPOSIT == null) 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; return SELLER_SECURITY_DEPOSIT;
} }
// This value must be lower than MIN_BUYER_SECURITY_DEPOSIT and 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) 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; return MIN_REFUND_AT_MEDIATED_DISPUTE;
} }

View File

@ -66,7 +66,6 @@ import monero.wallet.model.MoneroTxWallet;
import monero.wallet.model.MoneroWalletConfig; import monero.wallet.model.MoneroWalletConfig;
import monero.wallet.model.MoneroWalletListener; import monero.wallet.model.MoneroWalletListener;
import monero.wallet.model.MoneroWalletListenerI; import monero.wallet.model.MoneroWalletListenerI;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -314,9 +313,9 @@ public class XmrWalletService {
public MoneroTxWallet createDepositTx(Trade trade) { public MoneroTxWallet createDepositTx(Trade trade) {
Offer offer = trade.getProcessModel().getOffer(); Offer offer = trade.getProcessModel().getOffer();
String multisigAddress = trade.getProcessModel().getMultisigAddress(); String multisigAddress = trade.getProcessModel().getMultisigAddress();
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(trade instanceof MakerTrade ? trade.getOffer().getMakerFee() : trade.getTakerFee()); BigInteger tradeFee = trade instanceof MakerTrade ? trade.getOffer().getMakerFee() : trade.getTakerFee();
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(trade instanceof BuyerTrade ? Coin.ZERO : offer.getAmount()); BigInteger sendAmount = trade instanceof BuyerTrade ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(trade instanceof BuyerTrade ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit()); BigInteger securityDeposit = trade instanceof BuyerTrade ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
// thaw reserved outputs then create deposit tx // thaw reserved outputs then create deposit tx
MoneroWallet wallet = getWallet(); MoneroWallet wallet = getWallet();
@ -683,13 +682,13 @@ public class XmrWalletService {
private void notifyBalanceListeners() { private void notifyBalanceListeners() {
for (XmrBalanceListener balanceListener : balanceListeners) { for (XmrBalanceListener balanceListener : balanceListeners) {
Coin balance; BigInteger balance;
if (balanceListener.getSubaddressIndex() != null && balanceListener.getSubaddressIndex() != 0) balance = getBalanceForSubaddress(balanceListener.getSubaddressIndex()); if (balanceListener.getSubaddressIndex() != null && balanceListener.getSubaddressIndex() != 0) balance = getBalanceForSubaddress(balanceListener.getSubaddressIndex());
else balance = getAvailableBalance(); else balance = getAvailableBalance();
UserThread.execute(new Runnable() { // TODO (woodser): don't execute on UserThread UserThread.execute(new Runnable() { // TODO (woodser): don't execute on UserThread
@Override @Override
public void run() { public void run() {
balanceListener.onBalanceChanged(BigInteger.valueOf(balance.value)); balanceListener.onBalanceChanged(balance);
} }
}); });
} }
@ -847,7 +846,7 @@ public class XmrWalletService {
} }
public List<XmrAddressEntry> getFundedAvailableAddressEntries() { 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() { public List<XmrAddressEntry> getAddressEntryListAsImmutableList() {
@ -895,31 +894,31 @@ public class XmrWalletService {
.setIncludeOutputs(true)); .setIncludeOutputs(true));
} }
public Coin getBalanceForAddress(String address) { public BigInteger getBalanceForAddress(String address) {
return getBalanceForSubaddress(wallet.getAddressIndex(address).getIndex()); return getBalanceForSubaddress(wallet.getAddressIndex(address).getIndex());
} }
public Coin getBalanceForSubaddress(int subaddressIndex) { public BigInteger getBalanceForSubaddress(int subaddressIndex) {
return HavenoUtils.atomicUnitsToCoin(wallet.getBalance(0, subaddressIndex)); return wallet.getBalance(0, subaddressIndex);
} }
public Coin getAvailableBalanceForSubaddress(int subaddressIndex) { public BigInteger getAvailableBalanceForSubaddress(int subaddressIndex) {
return HavenoUtils.atomicUnitsToCoin(wallet.getUnlockedBalance(0, subaddressIndex)); return wallet.getUnlockedBalance(0, subaddressIndex);
} }
public Coin getBalance() { public BigInteger getBalance() {
return wallet != null ? HavenoUtils.atomicUnitsToCoin(wallet.getBalance(0)) : Coin.ZERO; return wallet != null ? wallet.getBalance(0) : BigInteger.valueOf(0);
} }
public Coin getAvailableBalance() { public BigInteger getAvailableBalance() {
return wallet != null ? HavenoUtils.atomicUnitsToCoin(wallet.getUnlockedBalance(0)) : Coin.ZERO; return wallet != null ? wallet.getUnlockedBalance(0) : BigInteger.valueOf(0);
} }
public Stream<XmrAddressEntry> getAddressEntriesForAvailableBalanceStream() { public Stream<XmrAddressEntry> getAddressEntriesForAvailableBalanceStream() {
Stream<XmrAddressEntry> availableAndPayout = Stream.concat(getAddressEntries(XmrAddressEntry.Context.TRADE_PAYOUT).stream(), getFundedAvailableAddressEntries().stream()); Stream<XmrAddressEntry> availableAndPayout = Stream.concat(getAddressEntries(XmrAddressEntry.Context.TRADE_PAYOUT).stream(), getFundedAvailableAddressEntries().stream());
Stream<XmrAddressEntry> available = Stream.concat(availableAndPayout, getAddressEntries(XmrAddressEntry.Context.ARBITRATOR).stream()); Stream<XmrAddressEntry> available = Stream.concat(availableAndPayout, getAddressEntries(XmrAddressEntry.Context.ARBITRATOR).stream());
available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).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) { public void addWalletListener(MoneroWalletListenerI listener) {

View File

@ -18,11 +18,12 @@
package bisq.core.monetary; package bisq.core.monetary;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.ParsingUtils; import bisq.core.util.ParsingUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Monetary; import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.ExchangeRate; import org.bitcoinj.utils.ExchangeRate;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
@ -33,7 +34,7 @@ import org.slf4j.LoggerFactory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Bitcoin price value with variable precision. * Monero price value with variable precision.
* <p> * <p>
* <br/> * <br/>
* We wrap an object implementing the {@link Monetary} interface from bitcoinj. We respect the * 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) 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) 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 else
throw new IllegalStateException("Monetary must be either of type Fiat or Altcoin"); 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(); Monetary monetary = volume.getMonetary();
if (monetary instanceof Fiat && this.monetary instanceof Fiat) 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) 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 else
return Coin.ZERO; return BigInteger.valueOf(0);
} }
public String getCurrencyCode() { public String getCurrencyCode() {

View File

@ -45,6 +45,7 @@ import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -104,8 +105,8 @@ public class CreateOfferService {
public Offer createAndGetOffer(String offerId, public Offer createAndGetOffer(String offerId,
OfferDirection direction, OfferDirection direction,
String currencyCode, String currencyCode,
Coin amount, BigInteger amount,
Coin minAmount, BigInteger minAmount,
Price price, Price price,
Coin txFee, Coin txFee,
boolean useMarketBasedPrice, boolean useMarketBasedPrice,
@ -128,8 +129,8 @@ public class CreateOfferService {
price == null ? null : price.getValue(), price == null ? null : price.getValue(),
useMarketBasedPrice, useMarketBasedPrice,
marketPriceMargin, marketPriceMargin,
amount.value, amount,
minAmount.value, minAmount,
buyerSecurityDepositAsDouble); buyerSecurityDepositAsDouble);
long creationTime = new Date().getTime(); long creationTime = new Date().getTime();
@ -146,8 +147,8 @@ public class CreateOfferService {
long priceAsLong = price != null ? price.getValue() : 0L; long priceAsLong = price != null ? price.getValue() : 0L;
double marketPriceMarginParam = useMarketBasedPriceValue ? marketPriceMargin : 0; double marketPriceMarginParam = useMarketBasedPriceValue ? marketPriceMargin : 0;
long amountAsLong = amount != null ? amount.getValue() : 0L; long amountAsLong = amount != null ? amount.longValueExact() : 0L;
long minAmountAsLong = minAmount != null ? minAmount.getValue() : 0L; long minAmountAsLong = minAmount != null ? minAmount.longValueExact() : 0L;
boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode); boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode);
String baseCurrencyCode = isCryptoCurrency ? currencyCode : Res.getBaseCurrencyCode(); String baseCurrencyCode = isCryptoCurrency ? currencyCode : Res.getBaseCurrencyCode();
String counterCurrencyCode = isCryptoCurrency ? Res.getBaseCurrencyCode() : currencyCode; String counterCurrencyCode = isCryptoCurrency ? Res.getBaseCurrencyCode() : currencyCode;
@ -155,10 +156,10 @@ public class CreateOfferService {
List<String> acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount); List<String> acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount);
String bankId = PaymentAccountUtil.getBankId(paymentAccount); String bankId = PaymentAccountUtil.getBankId(paymentAccount);
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount); List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
double sellerSecurityDeposit = getSellerSecurityDepositAsDouble(buyerSecurityDepositAsDouble); double sellerSecurityDepositAsDouble = getSellerSecurityDepositAsDouble(buyerSecurityDepositAsDouble);
Coin makerFeeAsCoin = HavenoUtils.getMakerFee(amount); BigInteger makerFee = HavenoUtils.getMakerFee(amount);
Coin buyerSecurityDepositAsCoin = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble); BigInteger buyerSecurityDeposit = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble);
Coin sellerSecurityDepositAsCoin = getSellerSecurityDeposit(amount, sellerSecurityDeposit); BigInteger sellerSecurityDeposit = getSellerSecurityDeposit(amount, sellerSecurityDepositAsDouble);
long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction); long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction);
long maxTradePeriod = paymentAccount.getMaxTradePeriod(); long maxTradePeriod = paymentAccount.getMaxTradePeriod();
@ -178,7 +179,7 @@ public class CreateOfferService {
buyerSecurityDepositAsDouble, buyerSecurityDepositAsDouble,
paymentAccount, paymentAccount,
currencyCode, currencyCode,
makerFeeAsCoin); makerFee);
OfferPayload offerPayload = new OfferPayload(offerId, OfferPayload offerPayload = new OfferPayload(offerId,
creationTime, creationTime,
@ -201,9 +202,9 @@ public class CreateOfferService {
acceptedBanks, acceptedBanks,
Version.VERSION, Version.VERSION,
xmrWalletService.getWallet().getHeight(), xmrWalletService.getWallet().getHeight(),
makerFeeAsCoin.value, makerFee.longValueExact(),
buyerSecurityDepositAsCoin.value, buyerSecurityDeposit.longValueExact(),
sellerSecurityDepositAsCoin.value, sellerSecurityDeposit.longValueExact(),
maxTradeLimit, maxTradeLimit,
maxTradePeriod, maxTradePeriod,
useAutoClose, useAutoClose,
@ -222,12 +223,12 @@ public class CreateOfferService {
return offer; return offer;
} }
public Coin getReservedFundsForOffer(OfferDirection direction, public BigInteger getReservedFundsForOffer(OfferDirection direction,
Coin amount, BigInteger amount,
double buyerSecurityDeposit, double buyerSecurityDeposit,
double sellerSecurityDeposit) { double sellerSecurityDeposit) {
Coin reservedFundsForOffer = getSecurityDeposit(direction, BigInteger reservedFundsForOffer = getSecurityDeposit(direction,
amount, amount,
buyerSecurityDeposit, buyerSecurityDeposit,
sellerSecurityDeposit); sellerSecurityDeposit);
@ -237,8 +238,8 @@ public class CreateOfferService {
return reservedFundsForOffer; return reservedFundsForOffer;
} }
public Coin getSecurityDeposit(OfferDirection direction, public BigInteger getSecurityDeposit(OfferDirection direction,
Coin amount, BigInteger amount,
double buyerSecurityDeposit, double buyerSecurityDeposit,
double sellerSecurityDeposit) { double sellerSecurityDeposit) {
return offerUtil.isBuyOffer(direction) ? return offerUtil.isBuyOffer(direction) ?
@ -260,26 +261,25 @@ public class CreateOfferService {
return marketPrice != null && marketPrice.isExternallyProvidedPrice(); return marketPrice != null && marketPrice.isExternallyProvidedPrice();
} }
private Coin getBuyerSecurityDeposit(Coin amount, double buyerSecurityDeposit) { private BigInteger getBuyerSecurityDeposit(BigInteger amount, double buyerSecurityDeposit) {
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(buyerSecurityDeposit, amount); BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(buyerSecurityDeposit, amount);
return getBoundedBuyerSecurityDeposit(percentOfAmountAsCoin); return getBoundedBuyerSecurityDeposit(percentOfAmount);
} }
private Coin getSellerSecurityDeposit(Coin amount, double sellerSecurityDeposit) { private BigInteger getSellerSecurityDeposit(BigInteger amount, double sellerSecurityDeposit) {
Coin amountAsCoin = (amount == null) ? Coin.ZERO : amount; BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(sellerSecurityDeposit, amount);
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(sellerSecurityDeposit, amountAsCoin); return getBoundedSellerSecurityDeposit(percentOfAmount);
return getBoundedSellerSecurityDeposit(percentOfAmountAsCoin);
} }
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 // 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. // MinBuyerSecurityDeposit from Restrictions.
return Coin.valueOf(Math.max(Restrictions.getMinBuyerSecurityDepositAsCoin().value, value.value)); 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 // 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. // MinSellerSecurityDeposit from Restrictions.
return Coin.valueOf(Math.max(Restrictions.getMinSellerSecurityDepositAsCoin().value, value.value)); return Restrictions.getMinSellerSecurityDeposit().max(value);
} }
} }

View File

@ -40,7 +40,6 @@ import bisq.common.util.JsonExclude;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
@ -49,6 +48,7 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import java.math.BigInteger;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Date; import java.util.Date;
@ -246,7 +246,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
} }
@Nullable @Nullable
public Volume getVolumeByAmount(Coin amount) { public Volume getVolumeByAmount(BigInteger amount) {
Price price = getPrice(); Price price = getPrice();
if (price == null || amount == null) { if (price == null || amount == null) {
return null; return null;
@ -291,34 +291,34 @@ public class Offer implements NetworkPayload, PersistablePayload {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// get the amount needed for the maker to reserve the offer // get the amount needed for the maker to reserve the offer
public Coin getReserveAmount() { public BigInteger getReserveAmount() {
Coin reserveAmount = getDirection() == OfferDirection.BUY ? getBuyerSecurityDeposit() : getSellerSecurityDeposit(); BigInteger reserveAmount = getDirection() == OfferDirection.BUY ? getBuyerSecurityDeposit() : getSellerSecurityDeposit();
if (getDirection() == OfferDirection.SELL) reserveAmount = reserveAmount.add(getAmount()); if (getDirection() == OfferDirection.SELL) reserveAmount = reserveAmount.add(getAmount());
return reserveAmount; return reserveAmount;
} }
public Coin getMakerFee() { public BigInteger getMakerFee() {
return Coin.valueOf(offerPayload.getMakerFee()); return BigInteger.valueOf(offerPayload.getMakerFee());
} }
public Coin getBuyerSecurityDeposit() { public BigInteger getBuyerSecurityDeposit() {
return Coin.valueOf(offerPayload.getBuyerSecurityDeposit()); return BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit());
} }
public Coin getSellerSecurityDeposit() { public BigInteger getSellerSecurityDeposit() {
return Coin.valueOf(offerPayload.getSellerSecurityDeposit()); return BigInteger.valueOf(offerPayload.getSellerSecurityDeposit());
} }
public Coin getMaxTradeLimit() { public BigInteger getMaxTradeLimit() {
return Coin.valueOf(offerPayload.getMaxTradeLimit()); return BigInteger.valueOf(offerPayload.getMaxTradeLimit());
} }
public Coin getAmount() { public BigInteger getAmount() {
return Coin.valueOf(offerPayload.getAmount()); return BigInteger.valueOf(offerPayload.getAmount());
} }
public Coin getMinAmount() { public BigInteger getMinAmount() {
return Coin.valueOf(offerPayload.getMinAmount()); return BigInteger.valueOf(offerPayload.getMinAmount());
} }
public boolean isRange() { public boolean isRange() {

View File

@ -208,7 +208,7 @@ public class OfferFilterService {
.map(paymentAccount -> accountAgeWitnessService.getMyTradeLimit(paymentAccount, .map(paymentAccount -> accountAgeWitnessService.getMyTradeLimit(paymentAccount,
offer.getCurrencyCode(), offer.getMirroredDirection())) offer.getCurrencyCode(), offer.getMirroredDirection()))
.orElse(0L); .orElse(0L);
long offerMinAmount = offer.getMinAmount().value; long offerMinAmount = offer.getMinAmount().longValueExact();
log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ", log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ",
accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null", accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null",
Coin.valueOf(myTradeLimit).toFriendlyString(), Coin.valueOf(myTradeLimit).toFriendlyString(),

View File

@ -22,14 +22,14 @@ import bisq.core.locale.Res;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import bisq.core.monetary.Volume; import bisq.core.monetary.Volume;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.HavenoUtils;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.MonetaryFormat; import org.bitcoinj.utils.MonetaryFormat;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -77,8 +77,8 @@ public class OfferForJson {
public OfferForJson(OfferDirection direction, public OfferForJson(OfferDirection direction,
String currencyCode, String currencyCode,
Coin minAmount, BigInteger minAmount,
Coin amount, BigInteger amount,
@Nullable Price price, @Nullable Price price,
Date date, Date date,
String id, String id,
@ -88,8 +88,8 @@ public class OfferForJson {
this.direction = direction; this.direction = direction;
this.currencyCode = currencyCode; this.currencyCode = currencyCode;
this.minAmount = minAmount.value; this.minAmount = minAmount.longValueExact();
this.amount = amount.value; this.amount = amount.longValueExact();
this.price = price.getValue(); this.price = price.getValue();
this.date = date.getTime(); this.date = date.getTime();
this.id = id; this.id = id;
@ -114,21 +114,21 @@ public class OfferForJson {
priceDisplayString = altcoinFormat.noCode().format(price.getMonetary()).toString(); priceDisplayString = altcoinFormat.noCode().format(price.getMonetary()).toString();
primaryMarketMinAmountDisplayString = altcoinFormat.noCode().format(getMinVolume().getMonetary()).toString(); primaryMarketMinAmountDisplayString = altcoinFormat.noCode().format(getMinVolume().getMonetary()).toString();
primaryMarketAmountDisplayString = altcoinFormat.noCode().format(getVolume().getMonetary()).toString(); primaryMarketAmountDisplayString = altcoinFormat.noCode().format(getVolume().getMonetary()).toString();
primaryMarketMinVolumeDisplayString = coinFormat.noCode().format(getMinAmountAsCoin()).toString(); primaryMarketMinVolumeDisplayString = HavenoUtils.formatToXmr(getMinAmount()).toString();
primaryMarketVolumeDisplayString = coinFormat.noCode().format(getAmountAsCoin()).toString(); primaryMarketVolumeDisplayString = HavenoUtils.formatToXmr(getAmount()).toString();
primaryMarketPrice = price.getValue(); primaryMarketPrice = price.getValue();
primaryMarketMinAmount = getMinVolume().getValue(); primaryMarketMinAmount = getMinVolume().getValue();
primaryMarketAmount = getVolume().getValue(); primaryMarketAmount = getVolume().getValue();
primaryMarketMinVolume = getMinAmountAsCoin().getValue(); primaryMarketMinVolume = getMinAmount().longValueExact();
primaryMarketVolume = getAmountAsCoin().getValue(); primaryMarketVolume = getAmount().longValueExact();
} else { } else {
primaryMarketDirection = direction; primaryMarketDirection = direction;
currencyPair = Res.getBaseCurrencyCode() + "/" + currencyCode; currencyPair = Res.getBaseCurrencyCode() + "/" + currencyCode;
priceDisplayString = fiatFormat.noCode().format(price.getMonetary()).toString(); priceDisplayString = fiatFormat.noCode().format(price.getMonetary()).toString();
primaryMarketMinAmountDisplayString = coinFormat.noCode().format(getMinAmountAsCoin()).toString(); primaryMarketMinAmountDisplayString = HavenoUtils.formatToXmr(getMinAmount()).toString();
primaryMarketAmountDisplayString = coinFormat.noCode().format(getAmountAsCoin()).toString(); primaryMarketAmountDisplayString = HavenoUtils.formatToXmr(getAmount()).toString();
primaryMarketMinVolumeDisplayString = fiatFormat.noCode().format(getMinVolume().getMonetary()).toString(); primaryMarketMinVolumeDisplayString = fiatFormat.noCode().format(getMinVolume().getMonetary()).toString();
primaryMarketVolumeDisplayString = fiatFormat.noCode().format(getVolume().getMonetary()).toString(); primaryMarketVolumeDisplayString = fiatFormat.noCode().format(getVolume().getMonetary()).toString();
@ -137,8 +137,8 @@ public class OfferForJson {
primaryMarketMinVolume = (long) MathUtils.scaleUpByPowerOf10(getMinVolume().getValue(), 4); primaryMarketMinVolume = (long) MathUtils.scaleUpByPowerOf10(getMinVolume().getValue(), 4);
primaryMarketVolume = (long) MathUtils.scaleUpByPowerOf10(getVolume().getValue(), 4); primaryMarketVolume = (long) MathUtils.scaleUpByPowerOf10(getVolume().getValue(), 4);
primaryMarketMinAmount = getMinAmountAsCoin().getValue(); primaryMarketMinAmount = getMinAmount().longValueExact();
primaryMarketAmount = getAmountAsCoin().getValue(); primaryMarketAmount = getAmount().longValueExact();
} }
} catch (Throwable t) { } catch (Throwable t) {
@ -150,19 +150,19 @@ public class OfferForJson {
return Price.valueOf(currencyCode, price); return Price.valueOf(currencyCode, price);
} }
private Coin getAmountAsCoin() { private BigInteger getAmount() {
return Coin.valueOf(amount); return BigInteger.valueOf(amount);
} }
private Coin getMinAmountAsCoin() { private BigInteger getMinAmount() {
return Coin.valueOf(minAmount); return BigInteger.valueOf(minAmount);
} }
private Volume getVolume() { private Volume getVolume() {
return getPrice().getVolumeByAmount(getAmountAsCoin()); return getPrice().getVolumeByAmount(getAmount());
} }
private Volume getMinVolume() { private Volume getMinVolume() {
return getPrice().getVolumeByAmount(getMinAmountAsCoin()); return getPrice().getVolumeByAmount(getMinAmount());
} }
} }

View File

@ -21,9 +21,9 @@ import bisq.common.app.Capabilities;
import bisq.common.app.Capability; import bisq.common.app.Capability;
import bisq.common.config.Config; import bisq.common.config.Config;
import bisq.common.util.Utilities; 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.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Map; import java.util.Map;
@ -37,7 +37,7 @@ public class OfferRestrictions {
return new Date().after(REQUIRE_TOR_NODE_ADDRESS_V3_DATE) && Config.baseCurrencyNetwork().isMainnet(); 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) { static boolean hasOfferMandatoryCapability(Offer offer, Capability mandatoryCapability) {
Map<String, String> extraDataMap = offer.getExtraDataMap(); Map<String, String> extraDataMap = offer.getExtraDataMap();

View File

@ -40,7 +40,6 @@ import bisq.common.app.Capabilities;
import bisq.common.app.Version; import bisq.common.app.Version;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionInput; import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
@ -49,6 +48,7 @@ import org.bitcoinj.utils.Fiat;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.math.BigInteger;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -129,7 +129,7 @@ public class OfferUtil {
* @param balance a wallet balance * @param balance a wallet balance
* @return true if balance >= cost * @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; return cost != null && balance.compareTo(cost) >= 0;
} }
@ -141,16 +141,15 @@ public class OfferUtil {
* @param balance a wallet balance * @param balance a wallet balance
* @return the wallet balance shortage for the given cost, else zero. * @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) { if (cost != null) {
Coin shortage = cost.subtract(balance); BigInteger shortage = cost.subtract(balance);
return shortage.isNegative() ? Coin.ZERO : shortage; return shortage.compareTo(BigInteger.valueOf(0)) < 0 ? BigInteger.valueOf(0) : shortage;
} else { } else {
return Coin.ZERO; return BigInteger.valueOf(0);
} }
} }
public double calculateManualPrice(double volumeAsDouble, double amountAsDouble) { public double calculateManualPrice(double volumeAsDouble, double amountAsDouble) {
return volumeAsDouble / amountAsDouble; return volumeAsDouble / amountAsDouble;
} }
@ -163,7 +162,7 @@ public class OfferUtil {
return offer != null && offer.getPaymentMethod().isBlockchain(); return offer != null && offer.getPaymentMethod().isBlockchain();
} }
public Optional<Volume> getFeeInUserFiatCurrency(Coin makerFee, public Optional<Volume> getFeeInUserFiatCurrency(BigInteger makerFee,
CoinFormatter formatter) { CoinFormatter formatter) {
String userCurrencyCode = preferences.getPreferredTradeCurrency().getCode(); String userCurrencyCode = preferences.getPreferredTradeCurrency().getCode();
if (CurrencyUtil.isCryptoCurrency(userCurrencyCode)) { if (CurrencyUtil.isCryptoCurrency(userCurrencyCode)) {
@ -216,8 +215,8 @@ public class OfferUtil {
public void validateOfferData(double buyerSecurityDeposit, public void validateOfferData(double buyerSecurityDeposit,
PaymentAccount paymentAccount, PaymentAccount paymentAccount,
String currencyCode, String currencyCode,
Coin makerFeeAsCoin) { BigInteger makerFee) {
checkNotNull(makerFeeAsCoin, "makerFee must not be null"); checkNotNull(makerFee, "makerFee must not be null");
checkNotNull(p2PService.getAddress(), "Address must not be null"); checkNotNull(p2PService.getAddress(), "Address must not be null");
checkArgument(buyerSecurityDeposit <= getMaxBuyerSecurityDepositAsPercent(), checkArgument(buyerSecurityDeposit <= getMaxBuyerSecurityDepositAsPercent(),
"securityDeposit must not exceed " + "securityDeposit must not exceed " +
@ -231,7 +230,7 @@ public class OfferUtil {
Res.get("offerbook.warning.paymentMethodBanned")); 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); MarketPrice marketPrice = priceFeedService.getMarketPrice(userCurrencyCode);
if (marketPrice != null && makerFee != null) { if (marketPrice != null && makerFee != null) {
long marketPriceAsLong = roundDoubleToLong(scaleUpByPowerOf10(marketPrice.getPrice(), Fiat.SMALLEST_UNIT_EXPONENT)); long marketPriceAsLong = roundDoubleToLong(scaleUpByPowerOf10(marketPrice.getPrice(), Fiat.SMALLEST_UNIT_EXPONENT));

View File

@ -73,7 +73,6 @@ import bisq.common.persistence.PersistenceManager;
import bisq.common.proto.network.NetworkEnvelope; import bisq.common.proto.network.NetworkEnvelope;
import bisq.common.proto.persistable.PersistedDataHost; import bisq.common.proto.persistable.PersistedDataHost;
import bisq.common.util.Tuple2; import bisq.common.util.Tuple2;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
@ -800,8 +799,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
} }
// get offer reserve amount // get offer reserve amount
Coin offerReserveAmountCoin = openOffer.getOffer().getReserveAmount(); BigInteger offerReserveAmount = openOffer.getOffer().getReserveAmount();
BigInteger offerReserveAmount = HavenoUtils.centinerosToAtomicUnits(offerReserveAmountCoin.value);
// handle sufficient available balance // handle sufficient available balance
if (xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0) { if (xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0) {
@ -814,7 +812,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
// otherwise sign and post offer // otherwise sign and post offer
else { else {
signAndPostOffer(openOffer, offerReserveAmountCoin, true, resultHandler, errorMessageHandler); signAndPostOffer(openOffer, offerReserveAmount, true, resultHandler, errorMessageHandler);
} }
return; return;
} }
@ -887,7 +885,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
} }
private void signAndPostOffer(OpenOffer openOffer, private void signAndPostOffer(OpenOffer openOffer,
Coin offerReserveAmount, BigInteger offerReserveAmount,
boolean useSavingsWallet, // TODO: remove this boolean useSavingsWallet, // TODO: remove this
TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
log.info("Signing and posting offer " + openOffer.getId()); log.info("Signing and posting offer " + openOffer.getId());
@ -980,8 +978,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
// verify maker's trade fee // verify maker's trade fee
Offer offer = new Offer(request.getOfferPayload()); Offer offer = new Offer(request.getOfferPayload());
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(HavenoUtils.getMakerFee(offer.getAmount())); BigInteger tradeFee = HavenoUtils.getMakerFee(offer.getAmount());
if (!tradeFee.equals(HavenoUtils.coinToAtomicUnits(offer.getMakerFee()))) { if (!tradeFee.equals(offer.getMakerFee())) {
errorMessage = "Wrong trade fee for offer " + request.offerId; errorMessage = "Wrong trade fee for offer " + request.offerId;
log.info(errorMessage); log.info(errorMessage);
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, 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) // 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 sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit()); BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
MoneroTx reserveTx = xmrWalletService.verifyTradeTx( MoneroTx reserveTx = xmrWalletService.verifyTradeTx(
tradeFee, tradeFee,
sendAmount, sendAmount,
@ -1011,8 +1009,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
SignedOffer signedOffer = new SignedOffer( SignedOffer signedOffer = new SignedOffer(
System.currentTimeMillis(), System.currentTimeMillis(),
signedOfferPayload.getId(), signedOfferPayload.getId(),
HavenoUtils.coinToAtomicUnits(offer.getAmount()).longValueExact(), offer.getAmount().longValueExact(),
HavenoUtils.coinToAtomicUnits(HavenoUtils.getMakerFee(offer.getAmount())).longValueExact(), HavenoUtils.getMakerFee(offer.getAmount()).longValueExact(),
request.getReserveTxHash(), request.getReserveTxHash(),
request.getReserveTxHex(), request.getReserveTxHex(),
request.getReserveTxKeyImages(), request.getReserveTxKeyImages(),

View File

@ -21,7 +21,6 @@ import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferUtil;
import bisq.core.offer.availability.OfferAvailabilityModel; import bisq.core.offer.availability.OfferAvailabilityModel;
import bisq.core.offer.messages.OfferAvailabilityRequest; import bisq.core.offer.messages.OfferAvailabilityRequest;
import bisq.core.trade.HavenoUtils; import bisq.core.trade.HavenoUtils;
@ -72,9 +71,9 @@ public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> {
offer.getId(), offer.getId(),
P2PService.getMyNodeAddress(), P2PService.getMyNodeAddress(),
p2PService.getKeyRing().getPubKeyRing(), p2PService.getKeyRing().getPubKeyRing(),
offer.getAmount().value, offer.getAmount().longValueExact(),
price.getValue(), price.getValue(),
HavenoUtils.getTakerFee(offer.getAmount()).value, HavenoUtils.getTakerFee(offer.getAmount()).longValueExact(),
user.getAccountId(), user.getAccountId(),
paymentAccountId, paymentAccountId,
paymentMethodId, paymentMethodId,

View File

@ -34,7 +34,8 @@ import bisq.common.taskrunner.Model;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import lombok.Getter; import lombok.Getter;
@ -50,7 +51,7 @@ import monero.wallet.model.MoneroTxWallet;
public class PlaceOfferModel implements Model { public class PlaceOfferModel implements Model {
// Immutable // Immutable
private final Offer offer; private final Offer offer;
private final Coin reservedFundsForOffer; private final BigInteger reservedFundsForOffer;
private final boolean useSavingsWallet; private final boolean useSavingsWallet;
private final P2PService p2PService; private final P2PService p2PService;
private final BtcWalletService walletService; private final BtcWalletService walletService;
@ -78,7 +79,7 @@ public class PlaceOfferModel implements Model {
private SignOfferResponse signOfferResponse; private SignOfferResponse signOfferResponse;
public PlaceOfferModel(Offer offer, public PlaceOfferModel(Offer offer,
Coin reservedFundsForOffer, BigInteger reservedFundsForOffer,
boolean useSavingsWallet, boolean useSavingsWallet,
P2PService p2PService, P2PService p2PService,
BtcWalletService walletService, BtcWalletService walletService,

View File

@ -23,14 +23,12 @@ import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection; import bisq.core.offer.OfferDirection;
import bisq.core.offer.placeoffer.PlaceOfferModel; import bisq.core.offer.placeoffer.PlaceOfferModel;
import bisq.core.trade.HavenoUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bitcoinj.core.Coin;
import monero.daemon.model.MoneroOutput; import monero.daemon.model.MoneroOutput;
import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroTxWallet;
@ -54,9 +52,9 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
model.getXmrWalletService().getConnectionsService().verifyConnection(); model.getXmrWalletService().getConnectionsService().verifyConnection();
// create reserve tx // create reserve tx
BigInteger makerFee = HavenoUtils.coinToAtomicUnits(offer.getMakerFee()); BigInteger makerFee = offer.getMakerFee();
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(offer.getDirection() == OfferDirection.BUY ? Coin.ZERO : offer.getAmount()); BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit()); BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(makerFee, sendAmount, securityDeposit, returnAddress); MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(makerFee, sendAmount, securityDeposit, returnAddress);

View File

@ -30,6 +30,8 @@ import org.bitcoinj.core.Coin;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.math.BigInteger;
public class ValidateOffer extends Task<PlaceOfferModel> { public class ValidateOffer extends Task<PlaceOfferModel> {
public ValidateOffer(TaskRunner<PlaceOfferModel> taskHandler, PlaceOfferModel model) { public ValidateOffer(TaskRunner<PlaceOfferModel> taskHandler, PlaceOfferModel model) {
super(taskHandler, model); super(taskHandler, model);
@ -42,13 +44,13 @@ public class ValidateOffer extends Task<PlaceOfferModel> {
runInterceptHook(); runInterceptHook();
// Coins // Coins
checkCoinNotNullOrZero(offer.getAmount(), "Amount"); checkBINotNullOrZero(offer.getAmount(), "Amount");
checkCoinNotNullOrZero(offer.getMinAmount(), "MinAmount"); checkBINotNullOrZero(offer.getMinAmount(), "MinAmount");
checkCoinNotNullOrZero(offer.getMakerFee(), "MakerFee"); checkBINotNullOrZero(offer.getMakerFee(), "MakerFee");
checkCoinNotNullOrZero(offer.getBuyerSecurityDeposit(), "buyerSecurityDeposit"); checkBINotNullOrZero(offer.getBuyerSecurityDeposit(), "buyerSecurityDeposit");
checkCoinNotNullOrZero(offer.getSellerSecurityDeposit(), "sellerSecurityDeposit"); checkBINotNullOrZero(offer.getSellerSecurityDeposit(), "sellerSecurityDeposit");
//checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model //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. // We remove those checks to be more flexible with future changes.
/*checkArgument(offer.getMakerFee().value >= FeeService.getMinMakerFee(offer.isCurrencyForMakerFeeBtc()).value, /*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());*/ "MinAmount is less than " + ProposalConsensus.getMinTradeAmount().toFriendlyString());*/
long maxAmount = model.getAccountAgeWitnessService().getMyTradeLimit(model.getUser().getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection()); long maxAmount = model.getAccountAgeWitnessService().getMyTradeLimit(model.getUser().getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection());
checkArgument(offer.getAmount().longValue() <= maxAmount, checkArgument(offer.getAmount().longValueExact() <= maxAmount,
"Amount is larger than " + HavenoUtils.coinToXmr(offer.getPaymentMethod().getMaxTradeLimitAsCoin(offer.getCurrencyCode())) + " XMR"); "Amount is larger than " + HavenoUtils.atomicUnitsToXmr(offer.getPaymentMethod().getMaxTradeLimit(offer.getCurrencyCode())) + " XMR");
checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount"); checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount");
checkNotNull(offer.getPrice(), "Price is null"); 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) { public static void checkCoinNotNullOrZero(Coin value, String name) {
checkNotNull(value, name + " is null"); checkNotNull(value, name + " is null");
checkArgument(value.isPositive(), checkArgument(value.isPositive(),

View File

@ -31,10 +31,9 @@ import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.HavenoUtils; import bisq.core.trade.HavenoUtils;
import bisq.common.taskrunner.Model; import bisq.common.taskrunner.Model;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import java.math.BigInteger;
import java.util.Objects; import java.util.Objects;
import lombok.Getter; 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.offer.OfferDirection.SELL;
import static bisq.core.util.VolumeUtil.getAdjustedVolumeForHalCash; import static bisq.core.util.VolumeUtil.getAdjustedVolumeForHalCash;
import static bisq.core.util.VolumeUtil.getRoundedFiatVolume; 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.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.bitcoinj.core.Coin.ZERO;
import static org.bitcoinj.core.Coin.valueOf;
@Slf4j @Slf4j
public class TakeOfferModel implements Model { public class TakeOfferModel implements Model {
@ -64,23 +60,23 @@ public class TakeOfferModel implements Model {
@Getter @Getter
private XmrAddressEntry addressEntry; private XmrAddressEntry addressEntry;
@Getter @Getter
private Coin amount; private BigInteger amount;
private Offer offer; private Offer offer;
private PaymentAccount paymentAccount; private PaymentAccount paymentAccount;
@Getter @Getter
private Coin securityDeposit; private BigInteger securityDeposit;
private boolean useSavingsWallet; private boolean useSavingsWallet;
@Getter @Getter
private Coin takerFee; private BigInteger takerFee;
@Getter @Getter
private Coin totalToPayAsCoin; private BigInteger totalToPay;
@Getter @Getter
private Coin missingCoin = ZERO; private BigInteger missingCoin = BigInteger.valueOf(0);
@Getter @Getter
private Coin totalAvailableBalance; private BigInteger totalAvailableBalance;
@Getter @Getter
private Coin availableBalance; private BigInteger availableBalance;
@Getter @Getter
private boolean isXmrWalletFunded; private boolean isXmrWalletFunded;
@Getter @Getter
@ -107,7 +103,7 @@ public class TakeOfferModel implements Model {
validateModelInputs(); validateModelInputs();
this.useSavingsWallet = useSavingsWallet; 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 this.securityDeposit = offer.getDirection() == SELL
? offer.getBuyerSecurityDeposit() ? offer.getBuyerSecurityDeposit()
: offer.getSellerSecurityDeposit(); : 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 // 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 // with dynamic fees. The mining fee for the takeOfferFee tx is deducted from
// the createOfferFee and not visible to the trader. // 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.add(amount)
: feeAndSecDeposit; : feeAndSecDeposit;
@ -155,9 +151,9 @@ public class TakeOfferModel implements Model {
private void updateBalance() { private void updateBalance() {
totalAvailableBalance = xmrWalletService.getAvailableBalance(); totalAvailableBalance = xmrWalletService.getAvailableBalance();
if (totalToPayAsCoin != null) availableBalance = minCoin(totalToPayAsCoin, totalAvailableBalance); if (totalToPay != null) availableBalance = totalToPay.min(totalAvailableBalance);
missingCoin = offerUtil.getBalanceShortage(totalToPayAsCoin, availableBalance); missingCoin = offerUtil.getBalanceShortage(totalToPay, availableBalance);
isXmrWalletFunded = offerUtil.isBalanceSufficient(totalToPayAsCoin, availableBalance); isXmrWalletFunded = offerUtil.isBalanceSufficient(totalToPay, availableBalance);
} }
private long getMaxTradeLimit() { private long getMaxTradeLimit() {
@ -167,15 +163,15 @@ public class TakeOfferModel implements Model {
} }
@NotNull @NotNull
public Coin getFundsNeededForTrade() { public BigInteger getFundsNeededForTrade() {
// If taking a buy offer, taker needs to reserve the offer.amt too. // 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() { private void validateModelInputs() {
checkNotNull(offer, "offer must not be null"); checkNotNull(offer, "offer must not be null");
checkNotNull(offer.getAmount(), "offer amount 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(offer.getPrice(), "offer price must not be null");
checkNotNull(paymentAccount, "payment account must not be null"); checkNotNull(paymentAccount, "payment account must not be null");
checkNotNull(addressEntry, "address entry 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.amount = null;
this.availableBalance = null; this.availableBalance = null;
this.isXmrWalletFunded = false; this.isXmrWalletFunded = false;
this.missingCoin = ZERO; this.missingCoin = BigInteger.valueOf(0);
this.offer = null; this.offer = null;
this.paymentAccount = null; this.paymentAccount = null;
this.securityDeposit = null; this.securityDeposit = null;
this.takerFee = null; this.takerFee = null;
this.totalAvailableBalance = null; this.totalAvailableBalance = null;
this.totalToPayAsCoin = null; this.totalToPay = null;
this.useSavingsWallet = true; this.useSavingsWallet = true;
this.volume = null; this.volume = null;
} }
@ -209,7 +205,7 @@ public class TakeOfferModel implements Model {
", amount=" + amount + "\n" + ", amount=" + amount + "\n" +
", securityDeposit=" + securityDeposit + "\n" + ", securityDeposit=" + securityDeposit + "\n" +
", takerFee=" + takerFee + "\n" + ", takerFee=" + takerFee + "\n" +
", totalToPayAsCoin=" + totalToPayAsCoin + "\n" + ", totalToPay=" + totalToPay + "\n" +
", missingCoin=" + missingCoin + "\n" + ", missingCoin=" + missingCoin + "\n" +
", totalAvailableBalance=" + totalAvailableBalance + "\n" + ", totalAvailableBalance=" + totalAvailableBalance + "\n" +
", availableBalance=" + availableBalance + "\n" + ", availableBalance=" + availableBalance + "\n" +

View File

@ -71,7 +71,7 @@ public class PaymentAccountUtil {
AccountAgeWitnessService accountAgeWitnessService) { AccountAgeWitnessService accountAgeWitnessService) {
boolean hasChargebackRisk = hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode()); boolean hasChargebackRisk = hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode());
boolean hasValidAccountAgeWitness = accountAgeWitnessService.getMyTradeLimit(paymentAccount, boolean hasValidAccountAgeWitness = accountAgeWitnessService.getMyTradeLimit(paymentAccount,
offer.getCurrencyCode(), offer.getMirroredDirection()) >= offer.getMinAmount().value; offer.getCurrencyCode(), offer.getMirroredDirection()) >= offer.getMinAmount().longValueExact();
return !hasChargebackRisk || hasValidAccountAgeWitness; return !hasChargebackRisk || hasValidAccountAgeWitness;
} }

View File

@ -18,8 +18,7 @@
package bisq.core.payment; package bisq.core.payment;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import bisq.core.trade.HavenoUtils;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -29,12 +28,14 @@ import com.google.common.annotations.VisibleForTesting;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.math.BigInteger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@Slf4j @Slf4j
@Singleton @Singleton
public class TradeLimits { 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 @Nullable
@Getter @Getter
private static TradeLimits INSTANCE; private static TradeLimits INSTANCE;
@ -57,7 +58,7 @@ public class TradeLimits {
* @see bisq.core.payment.payload.PaymentMethod * @see bisq.core.payment.payload.PaymentMethod
* @return the maximum trade limit * @return the maximum trade limit
*/ */
public Coin getMaxTradeLimit() { public BigInteger getMaxTradeLimit() {
return MAX_TRADE_LIMIT; return MAX_TRADE_LIMIT;
} }

View File

@ -77,8 +77,7 @@ import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config; import bisq.common.config.Config;
import bisq.common.proto.persistable.PersistablePayload; import bisq.common.proto.persistable.PersistablePayload;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; 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. // 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. // 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... // 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 BigInteger DEFAULT_TRADE_LIMIT_VERY_LOW_RISK = HavenoUtils.xmrToAtomicUnits(100);
private static final Coin DEFAULT_TRADE_LIMIT_LOW_RISK = Coin.parseCoin("50"); private static final BigInteger DEFAULT_TRADE_LIMIT_LOW_RISK = HavenoUtils.xmrToAtomicUnits(50);
private static final Coin DEFAULT_TRADE_LIMIT_MID_RISK = Coin.parseCoin("25"); private static final BigInteger DEFAULT_TRADE_LIMIT_MID_RISK = HavenoUtils.xmrToAtomicUnits(25);
private static final Coin DEFAULT_TRADE_LIMIT_HIGH_RISK = Coin.parseCoin("12.5"); private static final BigInteger DEFAULT_TRADE_LIMIT_HIGH_RISK = HavenoUtils.xmrToAtomicUnits(12.5);
public static final String UPHOLD_ID = "UPHOLD"; public static final String UPHOLD_ID = "UPHOLD";
public static final String MONEY_BEAM_ID = "MONEY_BEAM"; 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)), 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)), 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)), 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)), 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)), 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)), UPI = new PaymentMethod(UPI_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.05), getAssetCodes(UpiAccount.SUPPORTED_CURRENCIES)),
PAYTM = new PaymentMethod(PAYTM_ID, DAY, Coin.parseCoin("0.05"), getAssetCodes(PaytmAccount.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)), 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)), 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)), 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)), 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)), 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)), 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)), 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)), 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)), 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) { 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 maxTradeLimit The max. allowed trade amount in Bitcoin for that payment method (depending on charge back risk)
* @param supportedAssetCodes Supported asset codes. * @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.id = id;
this.maxTradePeriod = maxTradePeriod; this.maxTradePeriod = maxTradePeriod;
this.maxTradeLimit = maxTradeLimit.value; this.maxTradeLimit = maxTradeLimit.longValueExact();
this.supportedAssetCodes = supportedAssetCodes; this.supportedAssetCodes = supportedAssetCodes;
} }
// Used for dummy entries in payment methods list (SHOW_ALL) // Used for dummy entries in payment methods list (SHOW_ALL)
private PaymentMethod(String id) { 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) { public static PaymentMethod fromProto(protobuf.PaymentMethod proto) {
return new PaymentMethod(proto.getId(), return new PaymentMethod(proto.getId(),
proto.getMaxTradePeriod(), proto.getMaxTradePeriod(),
Coin.valueOf(proto.getMaxTradeLimit()), BigInteger.valueOf(proto.getMaxTradeLimit()),
proto.getSupportedAssetCodesList()); proto.getSupportedAssetCodesList());
} }
@ -456,44 +455,43 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
.findFirst(); .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! // Hack for SF as the smallest unit is 1 SF ;-( and price is about 3 BTC!
if (currencyCode.equals("SF")) if (currencyCode.equals("SF"))
return Coin.parseCoin("4"); return HavenoUtils.xmrToAtomicUnits(4);
// payment methods which define their own trade limits // 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)) { 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. // We use the class field maxTradeLimit only for mapping the risk factor.
long riskFactor; long riskFactor;
if (maxTradeLimit == DEFAULT_TRADE_LIMIT_VERY_LOW_RISK.value) if (maxTradeLimit == DEFAULT_TRADE_LIMIT_VERY_LOW_RISK.longValueExact())
riskFactor = 1; riskFactor = 1;
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_LOW_RISK.value) else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_LOW_RISK.longValueExact())
riskFactor = 2; riskFactor = 2;
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_MID_RISK.value) else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_MID_RISK.longValueExact())
riskFactor = 4; riskFactor = 4;
else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_HIGH_RISK.value) else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_HIGH_RISK.longValueExact())
riskFactor = 8; riskFactor = 8;
else { else {
riskFactor = 8; riskFactor = 8;
log.warn("maxTradeLimit is not matching one of our default values. We use highest risk factor. " + log.warn("maxTradeLimit is not matching one of our default values. We use highest risk factor. " +
"maxTradeLimit={}. PaymentMethod={}", "maxTradeLimit={}. PaymentMethod={}", maxTradeLimit, this);
Coin.valueOf(maxTradeLimit).toFriendlyString(), this);
} }
// get risk based trade limit // get risk based trade limit
TradeLimits tradeLimits = new TradeLimits(); TradeLimits tradeLimits = new TradeLimits();
long maxTradeLimit = tradeLimits.getMaxTradeLimit().value; long maxTradeLimit = tradeLimits.getMaxTradeLimit().longValueExact();
long riskBasedTradeLimit = tradeLimits.getRoundedRiskBasedTradeLimit(maxTradeLimit, riskFactor); // as centineros long riskBasedTradeLimit = tradeLimits.getRoundedRiskBasedTradeLimit(maxTradeLimit, riskFactor);
// if fiat and stagenet, cap offer amounts to avoid offers which cannot be taken // if fiat and stagenet, cap offer amounts to avoid offers which cannot be taken
boolean isFiat = CurrencyUtil.isFiatCurrency(currencyCode); boolean isFiat = CurrencyUtil.isFiatCurrency(currencyCode);
boolean isStagenet = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_STAGENET; boolean isStagenet = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_STAGENET;
if (isFiat && isStagenet && HavenoUtils.centinerosToXmr(riskBasedTradeLimit) > OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value) { if (isFiat && isStagenet && riskBasedTradeLimit > OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact()) {
riskBasedTradeLimit = HavenoUtils.xmrToCentineros(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value); riskBasedTradeLimit = OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact();
} }
return Coin.valueOf(riskBasedTradeLimit); return BigInteger.valueOf(riskBasedTradeLimit);
} }
public String getShortName() { public String getShortName() {

View File

@ -17,47 +17,39 @@
package bisq.core.payment.validation; package bisq.core.payment.validation;
import bisq.core.btc.wallet.Restrictions;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.util.FormattingUtils; import bisq.core.trade.HavenoUtils;
import bisq.core.util.coin.CoinFormatter;
import bisq.core.util.validation.NumberValidator; import bisq.core.util.validation.NumberValidator;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class BtcValidator extends NumberValidator { public class XmrValidator extends NumberValidator {
protected final CoinFormatter formatter;
@Nullable @Nullable
@Setter @Setter
protected Coin minValue; protected BigInteger minValue;
@Nullable @Nullable
@Setter @Setter
protected Coin maxValue; protected BigInteger maxValue;
@Nullable @Nullable
@Setter @Setter
@Getter @Getter
protected Coin maxTradeLimit; protected BigInteger maxTradeLimit;
@Inject @Inject
public BtcValidator(@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) { public XmrValidator() {
this.formatter = formatter;
} }
@Override @Override
public ValidationResult validate(String input) { public ValidationResult validate(String input) {
ValidationResult result = validateIfNotEmpty(input); ValidationResult result = validateIfNotEmpty(input);
@ -70,34 +62,20 @@ public class BtcValidator extends NumberValidator {
result = result.andValidation(input, result = result.andValidation(input,
this::validateIfNotZero, this::validateIfNotZero,
this::validateIfNotNegative, this::validateIfNotNegative,
this::validateIfNotFractionalBtcValue, this::validateIfNotFractionalXmrValue,
this::validateIfNotExceedsMaxTradeLimit, this::validateIfNotExceedsMaxTradeLimit,
this::validateIfNotExceedsMaxBtcValue, this::validateIfNotExceedsMaxValue,
this::validateIfNotUnderMinValue, this::validateIfNotUnderMinValue);
this::validateIfAboveDust);
} }
return result; return result;
} }
protected ValidationResult validateIfAboveDust(String input) { protected ValidationResult validateIfNotFractionalXmrValue(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) {
try { try {
BigDecimal bd = new BigDecimal(input); BigDecimal bd = new BigDecimal(input);
final BigDecimal satoshis = bd.movePointRight(8); final BigDecimal atomicUnits = bd.movePointRight(HavenoUtils.XMR_SMALLEST_UNIT_EXPONENT);
if (satoshis.scale() > 0) if (atomicUnits.scale() > 0)
return new ValidationResult(false, Res.get("validation.btc.fraction")); return new ValidationResult(false, Res.get("validation.btc.fraction"));
else else
return new ValidationResult(true); return new ValidationResult(true);
@ -106,11 +84,11 @@ public class BtcValidator extends NumberValidator {
} }
} }
protected ValidationResult validateIfNotExceedsMaxBtcValue(String input) { protected ValidationResult validateIfNotExceedsMaxValue(String input) {
try { try {
final Coin coin = Coin.parseCoin(input); final BigInteger amount = HavenoUtils.parseXmr(input);
if (maxValue != null && coin.compareTo(maxValue) > 0) if (maxValue != null && amount.compareTo(maxValue) > 0)
return new ValidationResult(false, Res.get("validation.btc.toLarge", formatter.formatCoinWithCode(maxValue))); return new ValidationResult(false, Res.get("validation.btc.toLarge", HavenoUtils.formatToXmrWithCode(maxValue)));
else else
return new ValidationResult(true); return new ValidationResult(true);
} catch (Throwable t) { } catch (Throwable t) {
@ -120,9 +98,9 @@ public class BtcValidator extends NumberValidator {
protected ValidationResult validateIfNotExceedsMaxTradeLimit(String input) { protected ValidationResult validateIfNotExceedsMaxTradeLimit(String input) {
try { try {
final Coin coin = Coin.parseCoin(input); final BigInteger amount = HavenoUtils.parseXmr(input);
if (maxTradeLimit != null && coin.compareTo(maxTradeLimit) > 0) if (maxTradeLimit != null && amount.compareTo(maxTradeLimit) > 0)
return new ValidationResult(false, Res.get("validation.btc.exceedsMaxTradeLimit", formatter.formatCoinWithCode(maxTradeLimit))); return new ValidationResult(false, Res.get("validation.btc.exceedsMaxTradeLimit", HavenoUtils.formatToXmrWithCode(maxTradeLimit)));
else else
return new ValidationResult(true); return new ValidationResult(true);
} catch (Throwable t) { } catch (Throwable t) {
@ -132,9 +110,9 @@ public class BtcValidator extends NumberValidator {
protected ValidationResult validateIfNotUnderMinValue(String input) { protected ValidationResult validateIfNotUnderMinValue(String input) {
try { try {
final Coin coin = Coin.parseCoin(input); final BigInteger amount = HavenoUtils.parseXmr(input);
if (minValue != null && coin.compareTo(minValue) < 0) if (minValue != null && amount.compareTo(minValue) < 0)
return new ValidationResult(false, Res.get("validation.btc.toSmall", formatter.formatCoinWithCode(minValue))); return new ValidationResult(false, Res.get("validation.btc.toSmall", HavenoUtils.formatToXmr(minValue)));
else else
return new ValidationResult(true); return new ValidationResult(true);
} catch (Throwable t) { } catch (Throwable t) {

View File

@ -56,7 +56,6 @@ import bisq.common.handlers.ResultHandler;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import bisq.common.util.Tuple2; import bisq.common.util.Tuple2;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import javafx.beans.property.IntegerProperty; 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.getMakerPayoutAddressString() : contract.getTakerPayoutAddressString()) :
(contract.isBuyerMakerAndSellerTaker() ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString()); (contract.isBuyerMakerAndSellerTaker() ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString());
String loserPayoutAddress = winnerPayoutAddress.equals(contract.getMakerPayoutAddressString()) ? 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 winnerPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount();
BigInteger loserPayoutAmount = HavenoUtils.coinToAtomicUnits(disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount()); BigInteger loserPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount();
// check sufficient balance // check sufficient balance
if (winnerPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Winner payout cannot be negative"); 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 // The amount we would get if we do a new trade with current price
Coin potentialAmountAtDisputeOpening = priceAtDisputeOpening.getAmountByVolume(contract.getTradeVolume()); BigInteger potentialAmountAtDisputeOpening = priceAtDisputeOpening.getAmountByVolume(contract.getTradeVolume());
Coin buyerSecurityDeposit = Coin.valueOf(offerPayload.getBuyerSecurityDeposit()); BigInteger buyerSecurityDeposit = BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit());
Coin minRefundAtMediatedDispute = Restrictions.getMinRefundAtMediatedDispute(); 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. // 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); BigInteger maxLossSecDeposit = buyerSecurityDeposit.subtract(minRefundAtMediatedDispute);
Coin tradeAmount = contract.getTradeAmount(); BigInteger tradeAmount = contract.getTradeAmount();
Coin potentialGain = potentialAmountAtDisputeOpening.subtract(tradeAmount).subtract(maxLossSecDeposit); BigInteger potentialGain = potentialAmountAtDisputeOpening.subtract(tradeAmount).subtract(maxLossSecDeposit);
String optionTradeDetails; String optionTradeDetails;
// We don't translate those strings (yet) as it is only displayed to mediators/arbitrators. // We don't translate those strings (yet) as it is only displayed to mediators/arbitrators.
String headline; String headline;
if (potentialGain.isPositive()) { if (potentialGain.compareTo(BigInteger.valueOf(0)) > 0) {
headline = "This might be a potential option trade!"; headline = "This might be a potential option trade!";
optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + potentialAmountAtDisputeOpening.toFriendlyString() + optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + HavenoUtils.formatToXmrWithCode(potentialAmountAtDisputeOpening) +
"\nMax loss of security deposit is: " + maxLossSecDeposit.toFriendlyString() + "\nMax loss of security deposit is: " + HavenoUtils.formatToXmrWithCode(maxLossSecDeposit) +
"\nPossible gain from an option trade is: " + potentialGain.toFriendlyString(); "\nPossible gain from an option trade is: " + HavenoUtils.formatToXmrWithCode(potentialGain);
} else { } else {
headline = "It does not appear to be an option trade."; headline = "It does not appear to be an option trade.";
optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + potentialAmountAtDisputeOpening.toFriendlyString() + optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + HavenoUtils.formatToXmrWithCode(potentialAmountAtDisputeOpening) +
"\nMax loss of security deposit is: " + maxLossSecDeposit.toFriendlyString() + "\nMax loss of security deposit is: " + HavenoUtils.formatToXmrWithCode(maxLossSecDeposit) +
"\nPossible loss from an option trade is: " + potentialGain.multiply(-1).toFriendlyString(); "\nPossible loss from an option trade is: " + HavenoUtils.formatToXmrWithCode(potentialGain.multiply(BigInteger.valueOf(-1)));
} }
String percentagePriceDetails = offerPayload.isUseMarketBasedPrice() ? String percentagePriceDetails = offerPayload.isUseMarketBasedPrice() ?
@ -1067,7 +1066,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
String priceInfoText = "System message: " + headline + String priceInfoText = "System message: " + headline +
"\n\nTrade price: " + contract.getPrice().toFriendlyString() + percentagePriceDetails + "\n\nTrade price: " + contract.getPrice().toFriendlyString() + percentagePriceDetails +
"\nTrade amount: " + tradeAmount.toFriendlyString() + "\nTrade amount: " + HavenoUtils.formatToXmrWithCode(tradeAmount) +
"\nPrice at dispute opening: " + priceAtDisputeOpening.toFriendlyString() + "\nPrice at dispute opening: " + priceAtDisputeOpening.toFriendlyString() +
optionTradeDetails; optionTradeDetails;

View File

@ -23,8 +23,6 @@ import bisq.common.proto.ProtoUtil;
import bisq.common.proto.network.NetworkPayload; import bisq.common.proto.network.NetworkPayload;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
@ -32,6 +30,7 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
import java.util.Optional; import java.util.Optional;
@ -206,20 +205,20 @@ public final class DisputeResult implements NetworkPayload {
return summaryNotesProperty; return summaryNotesProperty;
} }
public void setBuyerPayoutAmount(Coin buyerPayoutAmount) { public void setBuyerPayoutAmount(BigInteger buyerPayoutAmount) {
this.buyerPayoutAmount = buyerPayoutAmount.value; this.buyerPayoutAmount = buyerPayoutAmount.longValueExact();
} }
public Coin getBuyerPayoutAmount() { public BigInteger getBuyerPayoutAmount() {
return Coin.valueOf(buyerPayoutAmount); return BigInteger.valueOf(buyerPayoutAmount);
} }
public void setSellerPayoutAmount(Coin sellerPayoutAmount) { public void setSellerPayoutAmount(BigInteger sellerPayoutAmount) {
this.sellerPayoutAmount = sellerPayoutAmount.value; this.sellerPayoutAmount = sellerPayoutAmount.longValueExact();
} }
public Coin getSellerPayoutAmount() { public BigInteger getSellerPayoutAmount() {
return Coin.valueOf(sellerPayoutAmount); return BigInteger.valueOf(sellerPayoutAmount);
} }
public void setCloseDate(Date closeDate) { public void setCloseDate(Date closeDate) {

View File

@ -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 // 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 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); 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 // get expected payout amounts
BigInteger expectedWinnerAmount = HavenoUtils.coinToAtomicUnits(disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount()); BigInteger expectedWinnerAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount();
BigInteger expectedLoserAmount = HavenoUtils.coinToAtomicUnits(disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount()); BigInteger expectedLoserAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount();
// add any loss of precision to winner amount // add any loss of precision to winner amount
expectedWinnerAmount = expectedWinnerAmount.add(trade.getWallet().getUnlockedBalance().subtract(expectedWinnerAmount.add(expectedLoserAmount))); expectedWinnerAmount = expectedWinnerAmount.add(trade.getWallet().getUnlockedBalance().subtract(expectedWinnerAmount.add(expectedLoserAmount)));

View File

@ -20,8 +20,7 @@ package bisq.core.support.dispute.arbitration;
import bisq.core.account.witness.AccountAgeWitness; import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.security.PublicKey; import java.security.PublicKey;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -34,12 +33,12 @@ public class TraderDataItem {
private final PaymentAccountPayload paymentAccountPayload; private final PaymentAccountPayload paymentAccountPayload;
@EqualsAndHashCode.Include @EqualsAndHashCode.Include
private final AccountAgeWitness accountAgeWitness; private final AccountAgeWitness accountAgeWitness;
private final Coin tradeAmount; private final BigInteger tradeAmount;
private final PublicKey peersPubKey; private final PublicKey peersPubKey;
public TraderDataItem(PaymentAccountPayload paymentAccountPayload, public TraderDataItem(PaymentAccountPayload paymentAccountPayload,
AccountAgeWitness accountAgeWitness, AccountAgeWitness accountAgeWitness,
Coin tradeAmount, BigInteger tradeAmount,
PublicKey peersPubKey) { PublicKey peersPubKey) {
this.paymentAccountPayload = paymentAccountPayload; this.paymentAccountPayload = paymentAccountPayload;
this.accountAgeWitness = accountAgeWitness; this.accountAgeWitness = accountAgeWitness;

View File

@ -51,11 +51,10 @@ import bisq.common.crypto.KeyRing;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
import org.bitcoinj.core.Coin;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.math.BigInteger;
import java.util.Optional; import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -194,8 +193,8 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
Trade trade = tradeOptional.get(); Trade trade = tradeOptional.get();
if (trade.getDisputeState() == Trade.DisputeState.MEDIATION_REQUESTED || if (trade.getDisputeState() == Trade.DisputeState.MEDIATION_REQUESTED ||
trade.getDisputeState() == Trade.DisputeState.MEDIATION_STARTED_BY_PEER) { trade.getDisputeState() == Trade.DisputeState.MEDIATION_STARTED_BY_PEER) {
trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmount().value); trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmount().longValueExact());
trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmount().value); trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmount().longValueExact());
trade.setDisputeState(Trade.DisputeState.MEDIATION_CLOSED); trade.setDisputeState(Trade.DisputeState.MEDIATION_CLOSED);
@ -228,11 +227,11 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
Optional<Dispute> optionalDispute = findDispute(tradeId); Optional<Dispute> optionalDispute = findDispute(tradeId);
checkArgument(optionalDispute.isPresent(), "dispute must be present"); checkArgument(optionalDispute.isPresent(), "dispute must be present");
DisputeResult disputeResult = optionalDispute.get().getDisputeResultProperty().get(); DisputeResult disputeResult = optionalDispute.get().getDisputeResultProperty().get();
Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount(); BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount(); BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
ProcessModel processModel = trade.getProcessModel(); ProcessModel processModel = trade.getProcessModel();
processModel.setBuyerPayoutAmountFromMediation(buyerPayoutAmount.value); processModel.setBuyerPayoutAmountFromMediation(buyerPayoutAmount.longValueExact());
processModel.setSellerPayoutAmountFromMediation(sellerPayoutAmount.value); processModel.setSellerPayoutAmountFromMediation(sellerPayoutAmount.longValueExact());
DisputeProtocol tradeProtocol = (DisputeProtocol) tradeManager.getTradeProtocol(trade); DisputeProtocol tradeProtocol = (DisputeProtocol) tradeManager.getTradeProtocol(trade);
trade.setMediationResultState(MediationResultState.MEDIATION_RESULT_ACCEPTED); trade.setMediationResultState(MediationResultState.MEDIATION_RESULT_ACCEPTED);

View File

@ -9,8 +9,7 @@ import bisq.network.p2p.NodeAddress;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -22,8 +21,8 @@ import lombok.extern.slf4j.Slf4j;
public class ArbitratorTrade extends Trade { public class ArbitratorTrade extends Trade {
public ArbitratorTrade(Offer offer, public ArbitratorTrade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -35,7 +34,7 @@ public class ArbitratorTrade extends Trade {
} }
@Override @Override
public Coin getPayoutAmount() { public BigInteger getPayoutAmount() {
throw new RuntimeException("Arbitrator does not have a payout amount"); throw new RuntimeException("Arbitrator does not have a payout amount");
} }
@ -62,8 +61,8 @@ public class ArbitratorTrade extends Trade {
} }
return fromProto(new ArbitratorTrade( return fromProto(new ArbitratorTrade(
Offer.fromProto(proto.getOffer()), Offer.fromProto(proto.getOffer()),
Coin.valueOf(proto.getAmountAsLong()), BigInteger.valueOf(proto.getAmountAsLong()),
Coin.valueOf(proto.getTakerFeeAsLong()), BigInteger.valueOf(proto.getTakerFeeAsLong()),
proto.getPrice(), proto.getPrice(),
xmrWalletService, xmrWalletService,
processModel, processModel,

View File

@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -40,8 +39,8 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public BuyerAsMakerTrade(Offer offer, public BuyerAsMakerTrade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takeOfferFee, BigInteger takeOfferFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -84,8 +83,8 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
} }
BuyerAsMakerTrade trade = new BuyerAsMakerTrade( BuyerAsMakerTrade trade = new BuyerAsMakerTrade(
Offer.fromProto(proto.getOffer()), Offer.fromProto(proto.getOffer()),
Coin.valueOf(proto.getAmountAsLong()), BigInteger.valueOf(proto.getAmountAsLong()),
Coin.valueOf(proto.getTakerFeeAsLong()), BigInteger.valueOf(proto.getTakerFeeAsLong()),
proto.getPrice(), proto.getPrice(),
xmrWalletService, xmrWalletService,
processModel, processModel,

View File

@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -42,8 +41,8 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public BuyerAsTakerTrade(Offer offer, public BuyerAsTakerTrade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -87,8 +86,8 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
} }
return fromProto(new BuyerAsTakerTrade( return fromProto(new BuyerAsTakerTrade(
Offer.fromProto(proto.getOffer()), Offer.fromProto(proto.getOffer()),
Coin.valueOf(proto.getAmountAsLong()), BigInteger.valueOf(proto.getAmountAsLong()),
Coin.valueOf(proto.getTakerFeeAsLong()), BigInteger.valueOf(proto.getTakerFeeAsLong()),
proto.getPrice(), proto.getPrice(),
xmrWalletService, xmrWalletService,
processModel, processModel,

View File

@ -23,19 +23,19 @@ import bisq.core.trade.protocol.ProcessModel;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import org.bitcoinj.core.Coin;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.math.BigInteger;
@Slf4j @Slf4j
public abstract class BuyerTrade extends Trade { public abstract class BuyerTrade extends Trade {
BuyerTrade(Offer offer, BuyerTrade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -56,7 +56,7 @@ public abstract class BuyerTrade extends Trade {
} }
@Override @Override
public Coin getPayoutAmount() { public BigInteger getPayoutAmount() {
checkNotNull(getAmount(), "Invalid state: getTradeAmount() = null"); checkNotNull(getAmount(), "Invalid state: getTradeAmount() = null");
return checkNotNull(getOffer()).getBuyerSecurityDeposit().add(getAmount()); return checkNotNull(getOffer()).getBuyerSecurityDeposit().add(getAmount());
} }

View File

@ -48,8 +48,6 @@ import static bisq.core.util.FormattingUtils.formatPercentagePrice;
import static bisq.core.util.FormattingUtils.formatToPercentWithSymbol; import static bisq.core.util.FormattingUtils.formatToPercentWithSymbol;
import static bisq.core.util.VolumeUtil.formatVolume; import static bisq.core.util.VolumeUtil.formatVolume;
import static bisq.core.util.VolumeUtil.formatVolumeWithCode; import static bisq.core.util.VolumeUtil.formatVolumeWithCode;
import static org.bitcoinj.core.TransactionConfidence.ConfidenceType.BUILDING;
import static org.bitcoinj.core.TransactionConfidence.ConfidenceType.PENDING;
@Slf4j @Slf4j
@Singleton @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_AMOUNT = "closedTradesSummaryWindow.totalAmount.value";
private static final String I18N_KEY_TOTAL_TX_FEE = "closedTradesSummaryWindow.totalMinerFee.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_BTC = "closedTradesSummaryWindow.totalTradeFeeInBtc.value";
private static final String I18N_KEY_TOTAL_TRADE_FEE_BSQ = "closedTradesSummaryWindow.totalTradeFeeInBsq.value";
private final CoinFormatter btcFormatter; private final CoinFormatter btcFormatter;
private final ClosedTradableManager closedTradableManager; private final ClosedTradableManager closedTradableManager;
@ -72,7 +69,7 @@ public class ClosedTradableFormatter {
} }
public String getAmountAsString(Tradable tradable) { 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) { public String getTotalAmountWithVolumeAsString(Coin totalTradeAmount, Volume volume) {
@ -93,11 +90,11 @@ public class ClosedTradableFormatter {
} }
public String getBuyerSecurityDepositAsString(Tradable tradable) { public String getBuyerSecurityDepositAsString(Tradable tradable) {
return btcFormatter.formatCoin(tradable.getOffer().getBuyerSecurityDeposit()); return HavenoUtils.formatToXmr(tradable.getOffer().getBuyerSecurityDeposit());
} }
public String getSellerSecurityDepositAsString(Tradable tradable) { public String getSellerSecurityDepositAsString(Tradable tradable) {
return btcFormatter.formatCoin(tradable.getOffer().getSellerSecurityDeposit()); return HavenoUtils.formatToXmr(tradable.getOffer().getSellerSecurityDeposit());
} }
public String getTradeFeeAsString(Tradable tradable, boolean appendCode) { public String getTradeFeeAsString(Tradable tradable, boolean appendCode) {

View File

@ -41,6 +41,7 @@ import com.google.common.collect.ImmutableList;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import java.math.BigInteger;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
@ -229,8 +230,8 @@ public class ClosedTradableManager implements PersistedDataHost {
public long getBtcTradeFee(Tradable tradable) { public long getBtcTradeFee(Tradable tradable) {
return isMaker(tradable) ? return isMaker(tradable) ?
tradable.getOptionalMakerFee().orElse(Coin.ZERO).value : tradable.getOptionalMakerFee().orElse(BigInteger.valueOf(0)).longValueExact() :
tradable.getOptionalTakerFee().orElse(Coin.ZERO).value; tradable.getOptionalTakerFee().orElse(BigInteger.valueOf(0)).longValueExact();
} }
public boolean isMaker(Tradable tradable) { public boolean isMaker(Tradable tradable) {

View File

@ -33,8 +33,6 @@ import bisq.common.proto.network.NetworkPayload;
import bisq.common.util.JsonExclude; import bisq.common.util.JsonExclude;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import lombok.Value; import lombok.Value;
@ -44,6 +42,8 @@ import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import java.math.BigInteger;
@Slf4j @Slf4j
@Value @Value
public final class Contract implements NetworkPayload { public final class Contract implements NetworkPayload {
@ -209,8 +209,8 @@ public final class Contract implements NetworkPayload {
return makerPaymentMethodId; return makerPaymentMethodId;
} }
public Coin getTradeAmount() { public BigInteger getTradeAmount() {
return Coin.valueOf(tradeAmount); return BigInteger.valueOf(tradeAmount);
} }
public Volume getTradeVolume() { public Volume getTradeVolume() {

View File

@ -25,8 +25,6 @@ import bisq.core.trade.messages.InitTradeRequest;
import bisq.core.trade.messages.PaymentReceivedMessage; import bisq.core.trade.messages.PaymentReceivedMessage;
import bisq.core.trade.messages.PaymentSentMessage; import bisq.core.trade.messages.PaymentSentMessage;
import bisq.core.util.JsonUtil; import bisq.core.util.JsonUtil;
import bisq.core.util.ParsingUtils;
import bisq.core.util.coin.CoinUtil;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import bisq.common.config.Config; import bisq.common.config.Config;
@ -36,7 +34,6 @@ import bisq.common.crypto.Sig;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.MonetaryFormat;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
@ -68,9 +65,10 @@ import javax.annotation.Nullable;
@Slf4j @Slf4j
public class HavenoUtils { 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 LOOPBACK_HOST = "127.0.0.1"; // local loopback address to host Monero node
public static final String LOCALHOST = "localhost"; 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"); private static final BigInteger XMR_AU_MULTIPLIER = new BigInteger("1000000000000");
public static final DecimalFormat XMR_FORMATTER = new DecimalFormat("0.000000000000"); public static final DecimalFormat XMR_FORMATTER = new DecimalFormat("0.000000000000");
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); 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? public static ArbitrationManager arbitrationManager; // TODO: better way to share reference?
// ----------------------- CONVERSION UTILS -------------------------------
public static BigInteger coinToAtomicUnits(Coin coin) { public static BigInteger coinToAtomicUnits(Coin coin) {
return centinerosToAtomicUnits(coin.value); return centinerosToAtomicUnits(coin.value);
} }
public static BigInteger centinerosToAtomicUnits(long centineros) { 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) { public static double centinerosToXmr(long centineros) {
@ -95,12 +96,12 @@ public class HavenoUtils {
return atomicUnitsToCoin(centinerosToAtomicUnits(centineros)); return atomicUnitsToCoin(centinerosToAtomicUnits(centineros));
} }
public static long atomicUnitsToCentineros(long atomicUnits) { // TODO: atomic units should be BigInteger; remove this? public static long atomicUnitsToCentineros(long atomicUnits) {
return atomicUnits / CENTINEROS_AU_MULTIPLIER.longValue(); return atomicUnits / CENTINEROS_AU_MULTIPLIER;
} }
public static long atomicUnitsToCentineros(BigInteger atomicUnits) { 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) { public static Coin atomicUnitsToCoin(long atomicUnits) {
@ -131,11 +132,19 @@ public class HavenoUtils {
return atomicUnitsToXmr(coinToAtomicUnits(coin)); 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)); String formatted = XMR_FORMATTER.format(atomicUnitsToXmr(atomicUnits));
// strip trailing 0s // strip trailing 0s
@ -144,55 +153,87 @@ public class HavenoUtils {
formatted = formatted.substring(0, formatted.length() - 1); 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 @Nullable
public static Coin getMakerFee(@Nullable Coin amount) { public static BigInteger getMakerFee(@Nullable BigInteger amount) {
if (amount != null) { if (amount != null) {
Coin feePerXmr = getFeePerXmr(HavenoUtils.getMakerFeePerXmr(), amount); BigInteger feePerXmr = getFeePerXmr(HavenoUtils.getMakerFeePerXmr(), amount);
return CoinUtil.maxCoin(feePerXmr, HavenoUtils.getMinMakerFee()); return feePerXmr.max(HavenoUtils.getMinMakerFee());
} else { } else {
return null; return null;
} }
} }
@Nullable @Nullable
public static Coin getTakerFee(@Nullable Coin amount) { public static BigInteger getTakerFee(@Nullable BigInteger amount) {
if (amount != null) { if (amount != null) {
Coin feePerXmr = HavenoUtils.getFeePerXmr(HavenoUtils.getTakerFeePerXmr(), amount); BigInteger feePerXmr = HavenoUtils.getFeePerXmr(HavenoUtils.getTakerFeePerXmr(), amount);
return CoinUtil.maxCoin(feePerXmr, HavenoUtils.getMinTakerFee()); return feePerXmr.max(HavenoUtils.getMinTakerFee());
} else { } else {
return null; return null;
} }
} }
private static Coin getMakerFeePerXmr() { private static BigInteger getMakerFeePerXmr() {
return ParsingUtils.parseToCoin("0.001", xmrCoinFormat); return HavenoUtils.xmrToAtomicUnits(0.001);
} }
public static Coin getMinMakerFee() { public static BigInteger getMinMakerFee() {
return ParsingUtils.parseToCoin("0.00005", xmrCoinFormat); return HavenoUtils.xmrToAtomicUnits(0.00005);
} }
private static Coin getTakerFeePerXmr() { private static BigInteger getTakerFeePerXmr() {
return ParsingUtils.parseToCoin("0.003", xmrCoinFormat); return HavenoUtils.xmrToAtomicUnits(0.003);
} }
public static Coin getMinTakerFee() { public static BigInteger getMinTakerFee() {
return ParsingUtils.parseToCoin("0.00005", xmrCoinFormat); return HavenoUtils.xmrToAtomicUnits(0.00005);
} }
public static Coin getFeePerXmr(Coin feePerXmr, Coin amount) { public static BigInteger getFeePerXmr(BigInteger feePerXmr, BigInteger amount) {
double feePerBtcAsDouble = feePerXmr != null ? (double) feePerXmr.value : 0; BigDecimal feePerXmrAsDecimal = feePerXmr == null ? BigDecimal.valueOf(0) : new BigDecimal(feePerXmr);
double amountAsDouble = amount != null ? (double) amount.value : 0; BigDecimal amountAsDecimal = amount == null ? BigDecimal.valueOf(0) : new BigDecimal(amount);
double btcAsDouble = (double) Coin.COIN.value; BigDecimal xmrAsDecimal = new BigDecimal(HavenoUtils.xmrToAtomicUnits(1.0));
double fact = amountAsDouble / btcAsDouble; return feePerXmrAsDecimal.multiply(amountAsDecimal.divide(xmrAsDecimal)).toBigInteger();
return Coin.valueOf(Math.round(feePerBtcAsDouble * fact));
} }
// ----------------------------- OTHER UTILS ------------------------------
/** /**
* Get address to collect trade fees. * Get address to collect trade fees.
* *

View File

@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -42,8 +41,8 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public SellerAsMakerTrade(Offer offer, public SellerAsMakerTrade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -87,8 +86,8 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
} }
SellerAsMakerTrade trade = new SellerAsMakerTrade( SellerAsMakerTrade trade = new SellerAsMakerTrade(
Offer.fromProto(proto.getOffer()), Offer.fromProto(proto.getOffer()),
Coin.valueOf(proto.getAmountAsLong()), BigInteger.valueOf(proto.getAmountAsLong()),
Coin.valueOf(proto.getTakerFeeAsLong()), BigInteger.valueOf(proto.getTakerFeeAsLong()),
proto.getPrice(), proto.getPrice(),
xmrWalletService, xmrWalletService,
processModel, processModel,

View File

@ -26,8 +26,7 @@ import bisq.network.p2p.NodeAddress;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -42,8 +41,8 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public SellerAsTakerTrade(Offer offer, public SellerAsTakerTrade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -87,8 +86,8 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
} }
return fromProto(new SellerAsTakerTrade( return fromProto(new SellerAsTakerTrade(
Offer.fromProto(proto.getOffer()), Offer.fromProto(proto.getOffer()),
Coin.valueOf(proto.getAmountAsLong()), BigInteger.valueOf(proto.getAmountAsLong()),
Coin.valueOf(proto.getTakerFeeAsLong()), BigInteger.valueOf(proto.getTakerFeeAsLong()),
proto.getPrice(), proto.getPrice(),
xmrWalletService, xmrWalletService,
processModel, processModel,

View File

@ -18,25 +18,24 @@
package bisq.core.trade; package bisq.core.trade;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.trade.protocol.ProcessModel; import bisq.core.trade.protocol.ProcessModel;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import org.bitcoinj.core.Coin;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.math.BigInteger;
@Slf4j @Slf4j
public abstract class SellerTrade extends Trade { public abstract class SellerTrade extends Trade {
SellerTrade(Offer offer, SellerTrade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -57,7 +56,7 @@ public abstract class SellerTrade extends Trade {
} }
@Override @Override
public Coin getPayoutAmount() { public BigInteger getPayoutAmount() {
return checkNotNull(getOffer()).getSellerSecurityDeposit(); return checkNotNull(getOffer()).getSellerSecurityDeposit();
} }

View File

@ -26,6 +26,7 @@ import bisq.common.proto.persistable.PersistablePayload;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
import java.util.Optional; import java.util.Optional;
@ -54,7 +55,7 @@ public interface Tradable extends PersistablePayload {
return asTradeModel().map(Trade::getPrice).or(() -> Optional.ofNullable(getOffer().getPrice())); return asTradeModel().map(Trade::getPrice).or(() -> Optional.ofNullable(getOffer().getPrice()));
} }
default Optional<Coin> getOptionalAmount() { default Optional<BigInteger> getOptionalAmount() {
return asTradeModel().map(Trade::getAmount); return asTradeModel().map(Trade::getAmount);
} }
@ -66,11 +67,11 @@ public interface Tradable extends PersistablePayload {
return asTradeModel().map(Trade::getTxFee); return asTradeModel().map(Trade::getTxFee);
} }
default Optional<Coin> getOptionalTakerFee() { default Optional<BigInteger> getOptionalTakerFee() {
return asTradeModel().map(Trade::getTakerFee); 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())); return asTradeModel().map(Trade::getOffer).map(Offer::getMakerFee).or(() -> Optional.ofNullable(getOffer().getMakerFee()));
} }

View File

@ -375,7 +375,7 @@ public abstract class Trade implements Tradable, Model {
@Getter @Getter
transient final private Coin txFee; transient final private Coin txFee;
@Getter @Getter
transient final private Coin takerFee; transient final private BigInteger takerFee;
@Getter @Getter
transient final private XmrWalletService xmrWalletService; transient final private XmrWalletService xmrWalletService;
@ -402,9 +402,9 @@ public abstract class Trade implements Tradable, Model {
// Added in v1.2.0 // Added in v1.2.0
@Nullable @Nullable
transient private Coin tradeAmount; transient private BigInteger tradeAmount;
transient private ObjectProperty<Coin> tradeAmountProperty; transient private ObjectProperty<BigInteger> tradeAmountProperty;
transient private ObjectProperty<Volume> tradeVolumeProperty; transient private ObjectProperty<Volume> tradeVolumeProperty;
// Added in v1.1.6 // Added in v1.1.6
@ -469,8 +469,8 @@ public abstract class Trade implements Tradable, Model {
// maker // maker
protected Trade(Offer offer, protected Trade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin takerFee, // TODO (woodser): makerFee, takerFee, but not given one during construction BigInteger takerFee,
long tradePrice, long tradePrice,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
ProcessModel processModel, ProcessModel processModel,
@ -487,7 +487,7 @@ public abstract class Trade implements Tradable, Model {
this.processModel = processModel; this.processModel = processModel;
this.uid = uid; this.uid = uid;
this.takerFeeAsLong = takerFee.value; this.takerFeeAsLong = takerFee.longValueExact();
this.takeOfferDate = new Date().getTime(); this.takeOfferDate = new Date().getTime();
this.tradeListeners = new ArrayList<TradeListener>(); this.tradeListeners = new ArrayList<TradeListener>();
@ -503,9 +503,9 @@ public abstract class Trade implements Tradable, Model {
// taker // taker
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
protected Trade(Offer offer, protected Trade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin txFee, BigInteger txFee,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
@Nullable NodeAddress mediatorNodeAddress, // TODO (woodser): remove mediator, refund agent from trade @Nullable NodeAddress mediatorNodeAddress, // TODO (woodser): remove mediator, refund agent from trade
@Nullable NodeAddress refundAgentNodeAddress, @Nullable NodeAddress refundAgentNodeAddress,
@ -532,9 +532,9 @@ public abstract class Trade implements Tradable, Model {
// arbitrator // arbitrator
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
protected Trade(Offer offer, protected Trade(Offer offer,
Coin tradeAmount, BigInteger tradeAmount,
Coin txFee, Coin txFee,
Coin takerFee, BigInteger takerFee,
long tradePrice, long tradePrice,
NodeAddress makerNodeAddress, NodeAddress makerNodeAddress,
NodeAddress takerNodeAddress, NodeAddress takerNodeAddress,
@ -860,7 +860,7 @@ public abstract class Trade implements Tradable, Model {
boolean isBuyerMakerAndSellerTaker = getOffer().getDirection() == OfferDirection.BUY; boolean isBuyerMakerAndSellerTaker = getOffer().getDirection() == OfferDirection.BUY;
Contract contract = new Contract( Contract contract = new Contract(
getOffer().getOfferPayload(), getOffer().getOfferPayload(),
checkNotNull(getAmount()).value, checkNotNull(getAmount()).longValueExact(),
getPrice().getValue(), 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 ? 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 (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"); Preconditions.checkNotNull(buyerPayoutAddress, "Buyer payout address must not be null");
BigInteger sellerDepositAmount = multisigWallet.getTx(this.getSeller().getDepositTxHash()).getIncomingAmount(); BigInteger sellerDepositAmount = multisigWallet.getTx(this.getSeller().getDepositTxHash()).getIncomingAmount();
BigInteger buyerDepositAmount = multisigWallet.getTx(this.getBuyer().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 buyerPayoutAmount = buyerDepositAmount.add(tradeAmount);
BigInteger sellerPayoutAmount = sellerDepositAmount.subtract(tradeAmount); BigInteger sellerPayoutAmount = sellerDepositAmount.subtract(tradeAmount);
@ -956,7 +956,7 @@ public abstract class Trade implements Tradable, Model {
Contract contract = getContract(); Contract contract = getContract();
BigInteger sellerDepositAmount = wallet.getTx(getSeller().getDepositTxHash()).getIncomingAmount(); // TODO (woodser): redundancy of processModel.getPreparedDepositTxId() vs this.getDepositTxId() necessary or avoidable? 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 buyerDepositAmount = wallet.getTx(getBuyer().getDepositTxHash()).getIncomingAmount();
BigInteger tradeAmount = HavenoUtils.coinToAtomicUnits(getAmount()); BigInteger tradeAmount = getAmount();
// describe payout tx // describe payout tx
MoneroTxSet describedTxSet = wallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(payoutTxHex)); 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 // by mediators and we keep the confirm disabled to avoid that the seller can complete the trade
// without the penalty. // without the penalty.
long payoutAmountFromMediation = processModel.getSellerPayoutAmountFromMediation(); long payoutAmountFromMediation = processModel.getSellerPayoutAmountFromMediation();
long normalPayoutAmount = getSellerSecurityDeposit().value; long normalPayoutAmount = getSellerSecurityDeposit().longValueExact();
return payoutAmountFromMediation < normalPayoutAmount; return payoutAmountFromMediation < normalPayoutAmount;
} }
@ -1157,7 +1157,7 @@ public abstract class Trade implements Tradable, Model {
// Abstract // Abstract
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public abstract Coin getPayoutAmount(); public abstract BigInteger getPayoutAmount();
public abstract boolean confirmPermitted(); public abstract boolean confirmPermitted();
@ -1263,9 +1263,9 @@ public abstract class Trade implements Tradable, Model {
tradePeriodStateProperty.set(tradePeriodState); tradePeriodStateProperty.set(tradePeriodState);
} }
public void setAmount(Coin tradeAmount) { public void setAmount(BigInteger tradeAmount) {
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
amountAsLong = tradeAmount.value; amountAsLong = tradeAmount.longValueExact();
getAmountProperty().set(tradeAmount); getAmountProperty().set(tradeAmount);
getVolumeProperty().set(getVolume()); getVolumeProperty().set(getVolume());
} }
@ -1535,7 +1535,7 @@ public abstract class Trade implements Tradable, Model {
return tradePeriodStateProperty; return tradePeriodStateProperty;
} }
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() { public ReadOnlyObjectProperty<BigInteger> tradeAmountProperty() {
return tradeAmountProperty; return tradeAmountProperty;
} }
@ -1567,24 +1567,24 @@ public abstract class Trade implements Tradable, Model {
} }
@Nullable @Nullable
public Coin getAmount() { public BigInteger getAmount() {
if (tradeAmount == null) if (tradeAmount == null)
tradeAmount = Coin.valueOf(amountAsLong); tradeAmount = BigInteger.valueOf(amountAsLong);
return tradeAmount; return tradeAmount;
} }
public Coin getMakerFee() { public BigInteger getMakerFee() {
return offer.getMakerFee(); return offer.getMakerFee();
} }
public Coin getBuyerSecurityDeposit() { public BigInteger getBuyerSecurityDeposit() {
if (getBuyer().getDepositTxHash() == null) return null; 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; if (getSeller().getDepositTxHash() == null) return null;
return HavenoUtils.centinerosToCoin(getSeller().getSecurityDeposit()); return BigInteger.valueOf(getSeller().getSecurityDeposit());
} }
@Nullable @Nullable
@ -1627,7 +1627,7 @@ public abstract class Trade implements Tradable, Model {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// lazy initialization // lazy initialization
private ObjectProperty<Coin> getAmountProperty() { private ObjectProperty<BigInteger> getAmountProperty() {
if (tradeAmountProperty == null) if (tradeAmountProperty == null)
tradeAmountProperty = getAmount() != null ? new SimpleObjectProperty<>(getAmount()) : new SimpleObjectProperty<>(); tradeAmountProperty = getAmount() != null ? new SimpleObjectProperty<>(getAmount()) : new SimpleObjectProperty<>();
@ -1730,9 +1730,9 @@ public abstract class Trade implements Tradable, Model {
// set security deposits // set security deposits
if (getBuyer().getSecurityDeposit() == 0) { if (getBuyer().getSecurityDeposit() == 0) {
BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount(); BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(HavenoUtils.coinToAtomicUnits(getAmount())); BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
getBuyer().setSecurityDeposit(HavenoUtils.atomicUnitsToCentineros(buyerSecurityDeposit)); getBuyer().setSecurityDeposit(buyerSecurityDeposit.longValueExact());
getSeller().setSecurityDeposit(HavenoUtils.atomicUnitsToCentineros(sellerSecurityDeposit)); getSeller().setSecurityDeposit(sellerSecurityDeposit.longValueExact());
} }
// set deposits published state // set deposits published state

View File

@ -22,12 +22,13 @@ import bisq.core.offer.Offer;
import bisq.core.support.dispute.Dispute; import bisq.core.support.dispute.Dispute;
import org.bitcoinj.core.Address; import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionInput; import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint; import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import java.math.BigInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
import lombok.Getter; import lombok.Getter;
@ -130,7 +131,7 @@ public class TradeDataValidation {
// Check amount // Check amount
TransactionOutput output = delayedPayoutTx.getOutput(0); TransactionOutput output = delayedPayoutTx.getOutput(0);
Offer offer = checkNotNull(trade.getOffer()); Offer offer = checkNotNull(trade.getOffer());
Coin msOutputAmount = offer.getBuyerSecurityDeposit() BigInteger msOutputAmount = offer.getBuyerSecurityDeposit()
.add(offer.getSellerSecurityDeposit()) .add(offer.getSellerSecurityDeposit())
.add(checkNotNull(trade.getAmount())); .add(checkNotNull(trade.getAmount()));

View File

@ -88,6 +88,8 @@ import javafx.collections.ObservableList;
import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.KeyParameter;
import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.EasyBind;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -505,11 +507,11 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
} }
// get expected taker fee // 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 // create arbitrator trade
trade = new ArbitratorTrade(offer, trade = new ArbitratorTrade(offer,
Coin.valueOf(offer.getOfferPayload().getAmount()), BigInteger.valueOf(offer.getOfferPayload().getAmount()),
takerFee, takerFee,
offer.getOfferPayload().getPrice(), offer.getOfferPayload().getPrice(),
xmrWalletService, 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? openOfferManager.reserveOpenOffer(openOffer); // TODO (woodser): reserve offer if arbitrator? probably. or, arbitrator does not have open offer?
// get expected taker fee // get expected taker fee
Coin takerFee = HavenoUtils.getTakerFee(Coin.valueOf(offer.getOfferPayload().getAmount())); BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(offer.getOfferPayload().getAmount()));
Trade trade; Trade trade;
if (offer.isBuyOffer()) if (offer.isBuyOffer())
trade = new BuyerAsMakerTrade(offer, trade = new BuyerAsMakerTrade(offer,
Coin.valueOf(offer.getOfferPayload().getAmount()), BigInteger.valueOf(offer.getOfferPayload().getAmount()),
takerFee, takerFee,
offer.getOfferPayload().getPrice(), offer.getOfferPayload().getPrice(),
xmrWalletService, xmrWalletService,
@ -593,7 +595,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
request.getArbitratorNodeAddress()); request.getArbitratorNodeAddress());
else else
trade = new SellerAsMakerTrade(offer, trade = new SellerAsMakerTrade(offer,
Coin.valueOf(offer.getOfferPayload().getAmount()), BigInteger.valueOf(offer.getOfferPayload().getAmount()),
takerFee, takerFee,
offer.getOfferPayload().getPrice(), offer.getOfferPayload().getPrice(),
xmrWalletService, 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 // First we check if offer is still available then we create the trade with the protocol
public void onTakeOffer(Coin amount, public void onTakeOffer(BigInteger amount,
Coin takerFee, BigInteger takerFee,
Coin fundsNeededForTrade, BigInteger fundsNeededForTrade,
Offer offer, Offer offer,
String paymentAccountId, String paymentAccountId,
boolean useSavingsWallet, boolean useSavingsWallet,
@ -786,7 +788,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
trade.getProcessModel().setTradeMessage(model.getTradeRequest()); trade.getProcessModel().setTradeMessage(model.getTradeRequest());
trade.getProcessModel().setMakerSignature(model.getMakerSignature()); trade.getProcessModel().setMakerSignature(model.getMakerSignature());
trade.getProcessModel().setUseSavingsWallet(useSavingsWallet); trade.getProcessModel().setUseSavingsWallet(useSavingsWallet);
trade.getProcessModel().setFundsNeededForTradeAsLong(fundsNeededForTrade.value); trade.getProcessModel().setFundsNeededForTradeAsLong(fundsNeededForTrade.longValueExact());
trade.getMaker().setPubKeyRing(trade.getOffer().getPubKeyRing()); trade.getMaker().setPubKeyRing(trade.getOffer().getPubKeyRing());
trade.getSelf().setPubKeyRing(model.getPubKeyRing()); trade.getSelf().setPubKeyRing(model.getPubKeyRing());
trade.getSelf().setPaymentAccountId(paymentAccountId); trade.getSelf().setPaymentAccountId(paymentAccountId);

View File

@ -23,7 +23,6 @@ import bisq.common.crypto.PubKeyRing;
import bisq.common.crypto.Sig; import bisq.common.crypto.Sig;
import bisq.common.taskrunner.TaskRunner; import bisq.common.taskrunner.TaskRunner;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.messages.DepositRequest; import bisq.core.trade.messages.DepositRequest;
import bisq.core.trade.messages.DepositResponse; import bisq.core.trade.messages.DepositResponse;
@ -37,8 +36,6 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;
import org.bitcoinj.core.Coin;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import monero.daemon.MoneroDaemon; import monero.daemon.MoneroDaemon;
import monero.daemon.model.MoneroSubmitTxResult; import monero.daemon.model.MoneroSubmitTxResult;
@ -79,9 +76,9 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
Offer offer = trade.getOffer(); Offer offer = trade.getOffer();
boolean isFromTaker = trader == trade.getTaker(); boolean isFromTaker = trader == trade.getTaker();
boolean isFromBuyer = trader == trade.getBuyer(); boolean isFromBuyer = trader == trade.getBuyer();
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(isFromTaker ? trade.getTakerFee() : trade.getMakerFee()); BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(isFromBuyer ? Coin.ZERO : offer.getAmount()); BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit()); BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
String depositAddress = processModel.getMultisigAddress(); String depositAddress = processModel.getMultisigAddress();
// verify deposit tx // verify deposit tx

View File

@ -20,14 +20,11 @@ package bisq.core.trade.protocol.tasks;
import bisq.common.taskrunner.TaskRunner; import bisq.common.taskrunner.TaskRunner;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection; import bisq.core.offer.OfferDirection;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.messages.InitTradeRequest; import bisq.core.trade.messages.InitTradeRequest;
import bisq.core.trade.protocol.TradePeer; import bisq.core.trade.protocol.TradePeer;
import java.math.BigInteger; import java.math.BigInteger;
import org.bitcoinj.core.Coin;
import lombok.extern.slf4j.Slf4j; 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 // TODO (woodser): if signer online, should never be called by maker
// process reserve tx with expected values // process reserve tx with expected values
BigInteger tradeFee = HavenoUtils.coinToAtomicUnits(isFromTaker ? trade.getTakerFee() : trade.getMakerFee()); BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(isFromBuyer ? Coin.ZERO : offer.getAmount()); BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit()); BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
try { try {
trade.getXmrWalletService().verifyTradeTx( trade.getXmrWalletService().verifyTradeTx(
tradeFee, tradeFee,

View File

@ -57,9 +57,9 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask {
processModel.getOfferId(), processModel.getOfferId(),
request.getSenderNodeAddress(), request.getSenderNodeAddress(),
request.getPubKeyRing(), request.getPubKeyRing(),
trade.getAmount().value, trade.getAmount().longValueExact(),
trade.getPrice().getValue(), trade.getPrice().getValue(),
trade.getTakerFee().getValue(), trade.getTakerFee().longValueExact(),
request.getAccountId(), request.getAccountId(),
request.getPaymentAccountId(), request.getPaymentAccountId(),
request.getPaymentMethodId(), request.getPaymentMethodId(),

View File

@ -24,11 +24,8 @@ import bisq.core.trade.messages.InitTradeRequest;
import bisq.network.p2p.SendDirectMessageListener; import bisq.network.p2p.SendDirectMessageListener;
import bisq.common.app.Version; import bisq.common.app.Version;
import bisq.common.crypto.Sig;
import bisq.common.taskrunner.TaskRunner; import bisq.common.taskrunner.TaskRunner;
import com.google.common.base.Charsets;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -59,9 +56,9 @@ public class MakerSendInitTradeRequest extends TradeTask {
offer.getId(), offer.getId(),
processModel.getMyNodeAddress(), processModel.getMyNodeAddress(),
processModel.getPubKeyRing(), processModel.getPubKeyRing(),
offer.getAmount().value, offer.getAmount().longValueExact(),
trade.getPrice().getValue(), trade.getPrice().getValue(),
offer.getMakerFee().value, offer.getMakerFee().longValueExact(),
trade.getProcessModel().getAccountId(), trade.getProcessModel().getAccountId(),
offer.getMakerPaymentAccountId(), offer.getMakerPaymentAccountId(),
offer.getOfferPayload().getPaymentMethodId(), offer.getOfferPayload().getPaymentMethodId(),

View File

@ -27,7 +27,6 @@ import bisq.core.trade.messages.InitTradeRequest;
import bisq.core.trade.protocol.TradePeer; import bisq.core.trade.protocol.TradePeer;
import bisq.common.taskrunner.TaskRunner; import bisq.common.taskrunner.TaskRunner;
import org.bitcoinj.core.Coin;
import com.google.common.base.Charsets; 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.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
@Slf4j @Slf4j
@ -134,7 +134,7 @@ public class ProcessInitTradeRequest extends TradeTask {
// check trade amount // check trade amount
checkArgument(request.getTradeAmount() > 0); checkArgument(request.getTradeAmount() > 0);
trade.setAmount(Coin.valueOf(request.getTradeAmount())); trade.setAmount(BigInteger.valueOf(request.getTradeAmount()));
// persist trade // persist trade
processModel.getTradeManager().requestPersistence(); processModel.getTradeManager().requestPersistence();

View File

@ -20,14 +20,11 @@ package bisq.core.trade.protocol.tasks;
import bisq.common.taskrunner.TaskRunner; import bisq.common.taskrunner.TaskRunner;
import bisq.core.btc.model.XmrAddressEntry; import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.offer.OfferDirection; import bisq.core.offer.OfferDirection;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bitcoinj.core.Coin;
import monero.daemon.model.MoneroOutput; import monero.daemon.model.MoneroOutput;
import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroTxWallet;
@ -43,9 +40,9 @@ public class TakerReserveTradeFunds extends TradeTask {
runInterceptHook(); runInterceptHook();
// create reserve tx // create reserve tx
BigInteger takerFee = HavenoUtils.coinToAtomicUnits(trade.getTakerFee()); BigInteger takerFee = trade.getTakerFee();
BigInteger sendAmount = HavenoUtils.coinToAtomicUnits(trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getAmount() : Coin.ZERO); BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getAmount() : BigInteger.valueOf(0);
BigInteger securityDeposit = HavenoUtils.coinToAtomicUnits(trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getSellerSecurityDeposit() : trade.getOffer().getBuyerSecurityDeposit()); 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(); String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(takerFee, sendAmount, securityDeposit, returnAddress); MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(takerFee, sendAmount, securityDeposit, returnAddress);

View File

@ -24,6 +24,7 @@ import bisq.core.monetary.Volume;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection; import bisq.core.offer.OfferDirection;
import bisq.core.offer.OfferPayload; import bisq.core.offer.OfferPayload;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.util.JsonUtil; import bisq.core.util.JsonUtil;
import bisq.core.util.VolumeUtil; import bisq.core.util.VolumeUtil;
@ -44,12 +45,12 @@ import bisq.common.util.Utilities;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.ExchangeRate; import org.bitcoinj.utils.ExchangeRate;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -144,7 +145,7 @@ public final class TradeStatistics2 implements ProcessOncePersistableNetworkPayl
public TradeStatistics2(OfferPayload offerPayload, public TradeStatistics2(OfferPayload offerPayload,
Price tradePrice, Price tradePrice,
Coin tradeAmount, BigInteger tradeAmount,
Date tradeDate, Date tradeDate,
String makerDepositTxId, String makerDepositTxId,
String takerDepositTxId, String takerDepositTxId,
@ -160,7 +161,7 @@ public final class TradeStatistics2 implements ProcessOncePersistableNetworkPayl
offerPayload.getMinAmount(), offerPayload.getMinAmount(),
offerPayload.getId(), offerPayload.getId(),
tradePrice.getValue(), tradePrice.getValue(),
tradeAmount.value, tradeAmount.longValueExact(),
tradeDate.getTime(), tradeDate.getTime(),
makerDepositTxId, makerDepositTxId,
takerDepositTxId, takerDepositTxId,
@ -312,15 +313,15 @@ public final class TradeStatistics2 implements ProcessOncePersistableNetworkPayl
return baseCurrency.equals("XMR") ? counterCurrency : baseCurrency; return baseCurrency.equals("XMR") ? counterCurrency : baseCurrency;
} }
public Coin getTradeAmount() { public BigInteger getTradeAmount() {
return Coin.valueOf(tradeAmount); return BigInteger.valueOf(tradeAmount);
} }
public Volume getTradeVolume() { public Volume getTradeVolume() {
if (getPrice().getMonetary() instanceof Altcoin) { 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 { } 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); return VolumeUtil.getRoundedFiatVolume(volume);
} }
} }

View File

@ -168,7 +168,7 @@ public class TradeStatisticsConverter {
byte[] hash = tradeStatistics2.getHash(); byte[] hash = tradeStatistics2.getHash();
return new TradeStatistics3(tradeStatistics2.getCurrencyCode(), return new TradeStatistics3(tradeStatistics2.getCurrencyCode(),
tradeStatistics2.getPrice().getValue(), tradeStatistics2.getPrice().getValue(),
tradeStatistics2.getTradeAmount().getValue(), tradeStatistics2.getTradeAmount().longValueExact(),
tradeStatistics2.getOfferPaymentMethod(), tradeStatistics2.getOfferPaymentMethod(),
time, time,
mediator, mediator,

View File

@ -24,12 +24,12 @@ import bisq.core.monetary.Volume;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import org.bitcoinj.core.Coin;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.math.BigInteger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@ -65,12 +65,12 @@ public final class TradeStatisticsForJson {
primaryMarketTradeAmount = getTradeVolume() != null ? primaryMarketTradeAmount = getTradeVolume() != null ?
getTradeVolume().getValue() : getTradeVolume().getValue() :
0; 0;
primaryMarketTradeVolume = getTradeAmount().getValue(); primaryMarketTradeVolume = getTradeAmount().longValueExact();
} else { } else {
currencyPair = Res.getBaseCurrencyCode() + "/" + currency; 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 // 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); 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 // we use precision 4 for fiat but on the markets api we use precision 8 so we scale up by 10000
primaryMarketTradeVolume = getTradeVolume() != null ? primaryMarketTradeVolume = getTradeVolume() != null ?
(long) MathUtils.scaleUpByPowerOf10(getTradeVolume().getValue(), 4) : (long) MathUtils.scaleUpByPowerOf10(getTradeVolume().getValue(), 4) :
@ -86,8 +86,8 @@ public final class TradeStatisticsForJson {
return Price.valueOf(currency, tradePrice); return Price.valueOf(currency, tradePrice);
} }
public Coin getTradeAmount() { public BigInteger getTradeAmount() {
return Coin.valueOf(tradeAmount); return BigInteger.valueOf(tradeAmount);
} }
public Volume getTradeVolume() { public Volume getTradeVolume() {

View File

@ -22,6 +22,7 @@ import bisq.core.locale.Res;
import bisq.core.support.dispute.Dispute; import bisq.core.support.dispute.Dispute;
import bisq.core.support.dispute.mediation.MediationManager; import bisq.core.support.dispute.mediation.MediationManager;
import bisq.core.support.dispute.refund.RefundManager; import bisq.core.support.dispute.refund.RefundManager;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.txproof.AssetTxProofRequestsPerTrade; import bisq.core.trade.txproof.AssetTxProofRequestsPerTrade;
import bisq.core.trade.txproof.AssetTxProofResult; import bisq.core.trade.txproof.AssetTxProofResult;
@ -31,13 +32,12 @@ import bisq.network.Socks5ProxyProvider;
import bisq.common.handlers.FaultHandler; import bisq.common.handlers.FaultHandler;
import org.bitcoinj.core.Coin;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import java.math.BigInteger;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -327,11 +327,11 @@ class XmrTxProofRequestsPerTrade implements AssetTxProofRequestsPerTrade {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private boolean isTradeAmountAboveLimit(Trade trade) { private boolean isTradeAmountAboveLimit(Trade trade) {
Coin tradeAmount = trade.getAmount(); BigInteger tradeAmount = trade.getAmount();
Coin tradeLimit = Coin.valueOf(autoConfirmSettings.getTradeLimit()); BigInteger tradeLimit = BigInteger.valueOf(autoConfirmSettings.getTradeLimit());
if (tradeAmount != null && tradeAmount.isGreaterThan(tradeLimit)) { if (tradeAmount != null && tradeAmount.compareTo(tradeLimit) > 0) {
log.warn("Trade amount {} is higher than limit from auto-conf setting {}.", 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 true;
} }
return false; return false;

View File

@ -20,6 +20,7 @@ package bisq.core.util.coin;
import bisq.core.btc.wallet.Restrictions; import bisq.core.btc.wallet.Restrictions;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import bisq.core.monetary.Volume; import bisq.core.monetary.Volume;
import bisq.core.trade.HavenoUtils;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -29,6 +30,9 @@ import com.google.common.annotations.VisibleForTesting;
import static bisq.core.util.VolumeUtil.getAdjustedFiatVolume; import static bisq.core.util.VolumeUtil.getAdjustedFiatVolume;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import java.math.BigDecimal;
import java.math.BigInteger;
public class CoinUtil { 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) * @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) * @return The percentage value as double (e.g. 1% is 0.01)
*/ */
public static double getAsPercentPerBtc(Coin value) { public static double getAsPercentPerBtc(BigInteger value) {
return getAsPercentPerBtc(value, Coin.COIN); 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) * @return The percentage value as double (e.g. 1% is 0.01)
*/ */
public static double getAsPercentPerBtc(Coin part, Coin total) { public static double getAsPercentPerBtc(BigInteger part, BigInteger total) {
double asDouble = part != null ? (double) part.value : 0; BigDecimal partDecimal = part == null ? BigDecimal.valueOf(0) : new BigDecimal(part);
double btcAsDouble = total != null ? (double) total.value : 1; BigDecimal totalDecimal = total == null ? BigDecimal.valueOf(1) : new BigDecimal(total);
return MathUtils.roundDouble(asDouble / btcAsDouble, 4); return MathUtils.roundDouble(partDecimal.divide(totalDecimal).doubleValue(), 4);
} }
/** /**
* @param percent The percentage value as double (e.g. 1% is 0.01) * @param percent The percentage value as double (e.g. 1% is 0.01)
* @param amount The amount as Coin for the percentage calculation * @param amount The amount as atomic units for the percentage calculation
* @return The percentage as Coin (e.g. 1% of 1 BTC is 0.01 BTC) * @return The percentage as atomic units (e.g. 1% of 1 BTC is 0.01 BTC)
*/ */
public static Coin getPercentOfAmountAsCoin(double percent, Coin amount) { public static BigInteger getPercentOfAmount(double percent, BigInteger amount) {
double amountAsDouble = amount != null ? (double) amount.value : 0; if (amount == null) amount = BigInteger.valueOf(0);
return Coin.valueOf(Math.round(percent * amountAsDouble)); 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. * @param maxTradeLimit The max. trade limit of the users account, in satoshis.
* @return The adjusted amount * @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); 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); 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 * Calculate the possibly adjusted amount for {@code amount}, taking into account the
* {@code price} and {@code maxTradeLimit} and {@code factor}. * {@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 price Price used in relation to that amount.
* @param maxTradeLimit The max. trade limit of the users account, in satoshis. * @param maxTradeLimit The max. trade limit of the users account, in satoshis.
* @param factor The factor used for rounding. E.g. 1 means rounded to units of * @param factor The factor used for rounding. E.g. 1 means rounded to units of
@ -105,10 +109,10 @@ public class CoinUtil {
* @return The adjusted amount * @return The adjusted amount
*/ */
@VisibleForTesting @VisibleForTesting
static Coin getAdjustedAmount(Coin amount, Price price, long maxTradeLimit, int factor) { static BigInteger getAdjustedAmount(BigInteger amount, Price price, long maxTradeLimit, int factor) {
checkArgument( checkArgument(
amount.getValue() >= 10_000, amount.longValueExact() >= HavenoUtils.xmrToAtomicUnits(0.0001).longValueExact(),
"amount needs to be above minimum of 10k satoshis" "amount needs to be above minimum of 0.0001 xmr" // TODO: update amount for XMR
); );
checkArgument( checkArgument(
factor > 0, factor > 0,
@ -118,17 +122,17 @@ public class CoinUtil {
// 10 EUR in case of HalCash. // 10 EUR in case of HalCash.
Volume smallestUnitForVolume = Volume.parse(String.valueOf(factor), price.getCurrencyCode()); Volume smallestUnitForVolume = Volume.parse(String.valueOf(factor), price.getCurrencyCode());
if (smallestUnitForVolume.getValue() <= 0) if (smallestUnitForVolume.getValue() <= 0)
return Coin.ZERO; return BigInteger.valueOf(0);
Coin smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume); BigInteger smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume);
long minTradeAmount = Restrictions.getMinTradeAmount().value; long minTradeAmount = Restrictions.getMinTradeAmount().longValueExact();
// We use 10 000 satoshi as min allowed amount // We use 10 000 satoshi as min allowed amount
checkArgument( checkArgument(
minTradeAmount >= 10_000, minTradeAmount >= HavenoUtils.xmrToAtomicUnits(0.0001).longValueExact(),
"MinTradeAmount must be at least 10k satoshis" "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 // We don't allow smaller amount values than smallestUnitForAmount
boolean useSmallestUnitForAmount = amount.compareTo(smallestUnitForAmount) < 0; boolean useSmallestUnitForAmount = amount.compareTo(smallestUnitForAmount) < 0;
@ -137,21 +141,22 @@ public class CoinUtil {
? getAdjustedFiatVolume(price.getVolumeByAmount(smallestUnitForAmount), factor) ? getAdjustedFiatVolume(price.getVolumeByAmount(smallestUnitForAmount), factor)
: getAdjustedFiatVolume(price.getVolumeByAmount(amount), factor); : getAdjustedFiatVolume(price.getVolumeByAmount(amount), factor);
if (volume.getValue() <= 0) 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 // From that adjusted volume we calculate back the amount. It might be a bit different as
// the amount used as input before due rounding. // the amount used as input before due rounding.
Coin amountByVolume = price.getAmountByVolume(volume); BigInteger amountByVolume = price.getAmountByVolume(volume);
// For the amount we allow only 4 decimal places // 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 // If we are above our trade limit we reduce the amount by the smallestUnitForAmount
while (adjustedAmount > maxTradeLimit) { while (adjustedAmount > maxTradeLimit) {
adjustedAmount -= smallestUnitForAmount.value; adjustedAmount -= smallestUnitForAmount.longValueExact();
} }
adjustedAmount = Math.max(minTradeAmount, adjustedAmount); adjustedAmount = Math.max(minTradeAmount, adjustedAmount);
adjustedAmount = Math.min(maxTradeLimit, adjustedAmount); adjustedAmount = Math.min(maxTradeLimit, adjustedAmount);
return Coin.valueOf(adjustedAmount); return BigInteger.valueOf(adjustedAmount);
} }
} }

View File

@ -31,11 +31,11 @@ import bisq.common.crypto.KeyRing;
import bisq.common.crypto.Sig; import bisq.common.crypto.Sig;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import java.math.BigInteger;
import java.security.KeyPair; import java.security.KeyPair;
import java.time.Instant; import java.time.Instant;
@ -354,7 +354,7 @@ public class SignedWitnessServiceTest {
when(keyRing.getSignatureKeyPair()).thenReturn(signerKeyPair); when(keyRing.getSignatureKeyPair()).thenReturn(signerKeyPair);
AccountAgeWitness accountAgeWitness = new AccountAgeWitness(account1DataHash, accountCreationTime); 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()); verify(p2pService, never()).addPersistableNetworkPayload(any(PersistableNetworkPayload.class), anyBoolean());
} }

View File

@ -32,7 +32,7 @@ import bisq.core.support.dispute.DisputeResult;
import bisq.core.support.dispute.arbitration.TraderDataItem; import bisq.core.support.dispute.arbitration.TraderDataItem;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.trade.Contract; import bisq.core.trade.Contract;
import bisq.core.trade.HavenoUtils;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService; import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
@ -44,7 +44,6 @@ import bisq.common.crypto.PubKeyRing;
import bisq.common.crypto.Sig; import bisq.common.crypto.Sig;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
import java.security.KeyPair; import java.security.KeyPair;
@ -52,7 +51,6 @@ import java.security.PublicKey;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -227,7 +225,7 @@ public class AccountAgeWitnessServiceTest {
when(chargeBackRisk.hasChargebackRisk(any(), any())).thenReturn(true); when(chargeBackRisk.hasChargebackRisk(any(), any())).thenReturn(true);
when(contract.getPaymentMethodId()).thenReturn(PaymentMethod.SEPA_ID); 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.getBuyerPubKeyRing()).thenReturn(buyerPubKeyRing);
when(contract.getSellerPubKeyRing()).thenReturn(sellerPubKeyRing); when(contract.getSellerPubKeyRing()).thenReturn(sellerPubKeyRing);
when(contract.getOfferPayload()).thenReturn(mock(OfferPayload.class)); when(contract.getOfferPayload()).thenReturn(mock(OfferPayload.class));
@ -357,7 +355,7 @@ public class AccountAgeWitnessServiceTest {
signerKeyRing.getSignatureKeyPair().getPublic().getEncoded(), signerKeyRing.getSignatureKeyPair().getPublic().getEncoded(),
witnessOwnerPubKey.getEncoded(), witnessOwnerPubKey.getEncoded(),
time, time,
SignedWitnessService.MINIMUM_TRADE_AMOUNT_FOR_SIGNING.value); SignedWitnessService.MINIMUM_TRADE_AMOUNT_FOR_SIGNING.longValueExact());
signedWitnessService.addToMap(signedWitness); signedWitnessService.addToMap(signedWitness);
} }

View File

@ -4,8 +4,7 @@ import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.support.dispute.arbitration.TraderDataItem; import bisq.core.support.dispute.arbitration.TraderDataItem;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import org.bitcoinj.core.Coin; import java.math.BigInteger;
import java.security.PublicKey; import java.security.PublicKey;
import org.junit.Before; import org.junit.Before;
@ -44,11 +43,11 @@ public class TraderDataItemTest {
public void setup() { public void setup() {
accountAgeWitness1 = new AccountAgeWitness(hash1, 123); accountAgeWitness1 = new AccountAgeWitness(hash1, 123);
accountAgeWitness2 = new AccountAgeWitness(hash2, 124); 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)); 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)); 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)); mock(PublicKey.class));
} }

View File

@ -27,14 +27,16 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.math.BigInteger;
public class CoinUtilTest { public class CoinUtilTest {
@Test @Test
public void testGetFeePerBtc() { public void testGetFeePerBtc() {
assertEquals(Coin.parseCoin("1"), HavenoUtils.getFeePerXmr(Coin.parseCoin("1"), Coin.parseCoin("1"))); assertEquals(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.xmrToAtomicUnits(1)));
assertEquals(Coin.parseCoin("0.1"), HavenoUtils.getFeePerXmr(Coin.parseCoin("0.1"), Coin.parseCoin("1"))); assertEquals(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(1)));
assertEquals(Coin.parseCoin("0.01"), HavenoUtils.getFeePerXmr(Coin.parseCoin("0.1"), Coin.parseCoin("0.1"))); assertEquals(HavenoUtils.xmrToAtomicUnits(0.01), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1)));
assertEquals(Coin.parseCoin("0.015"), HavenoUtils.getFeePerXmr(Coin.parseCoin("0.3"), Coin.parseCoin("0.05"))); assertEquals(HavenoUtils.xmrToAtomicUnits(0.015), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.3), HavenoUtils.xmrToAtomicUnits(0.05)));
} }
@Test @Test
@ -57,52 +59,52 @@ public class CoinUtilTest {
@Test @Test
public void testGetAdjustedAmount() { public void testGetAdjustedAmount() {
Coin result = CoinUtil.getAdjustedAmount( BigInteger result = CoinUtil.getAdjustedAmount(
Coin.valueOf(100_000), HavenoUtils.xmrToAtomicUnits(0.001),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
20_000_000, HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
1); 1);
assertEquals( assertEquals(
"Minimum trade amount allowed should be adjusted to the smallest trade allowed.", "Minimum trade amount allowed should be adjusted to the smallest trade allowed.",
"0.001 BTC", "0.001 XMR",
result.toFriendlyString() HavenoUtils.formatToXmrWithCode(result)
); );
try { try {
CoinUtil.getAdjustedAmount( CoinUtil.getAdjustedAmount(
Coin.ZERO, BigInteger.valueOf(0),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
20_000_000, HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
1); 1);
fail("Expected IllegalArgumentException to be thrown when amount is too low."); fail("Expected IllegalArgumentException to be thrown when amount is too low.");
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
assertEquals( assertEquals(
"Unexpected exception message.", "Unexpected exception message.",
"amount needs to be above minimum of 10k satoshis", "amount needs to be above minimum of 0.0001 xmr",
iae.getMessage() iae.getMessage()
); );
} }
result = CoinUtil.getAdjustedAmount( result = CoinUtil.getAdjustedAmount(
Coin.valueOf(1_000_000), HavenoUtils.xmrToAtomicUnits(0.01),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
20_000_000, HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
1); 1);
assertEquals( assertEquals(
"Minimum allowed trade amount should not be adjusted.", "Minimum allowed trade amount should not be adjusted.",
"0.01 BTC", "0.01 XMR",
result.toFriendlyString() HavenoUtils.formatToXmrWithCode(result)
); );
result = CoinUtil.getAdjustedAmount( result = CoinUtil.getAdjustedAmount(
Coin.valueOf(100_000), HavenoUtils.xmrToAtomicUnits(0.001),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
1_000_000, HavenoUtils.xmrToAtomicUnits(0.1).longValueExact(),
1); 1);
assertEquals( assertEquals(
"Minimum trade amount allowed should respect maxTradeLimit and factor, if possible.", "Minimum trade amount allowed should respect maxTradeLimit and factor, if possible.",
"0.001 BTC", "0.001 XMR",
result.toFriendlyString() HavenoUtils.formatToXmrWithCode(result)
); );
// TODO(chirhonul): The following seems like it should raise an exception or otherwise fail. // 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. // 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.. // Basically the given constraints (maxTradeLimit vs factor) are impossible to both fulfill..
result = CoinUtil.getAdjustedAmount( result = CoinUtil.getAdjustedAmount(
Coin.valueOf(100_000), HavenoUtils.xmrToAtomicUnits(0.001),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
5_000, HavenoUtils.xmrToAtomicUnits(0.00005).longValueExact(),
1); 1);
assertEquals( assertEquals(
"Minimum trade amount allowed with low maxTradeLimit should still respect that limit, even if result does not respect the factor specified.", "Minimum trade amount allowed with low maxTradeLimit should still respect that limit, even if result does not respect the factor specified.",
"0.00005 BTC", "0.00005 XMR",
result.toFriendlyString() HavenoUtils.formatToXmrWithCode(result)
); );
} }
} }

View File

@ -3,7 +3,6 @@ package bisq.daemon.grpc;
import bisq.core.api.CoreApi; import bisq.core.api.CoreApi;
import bisq.core.support.dispute.Attachment; import bisq.core.support.dispute.Attachment;
import bisq.core.support.dispute.DisputeResult; import bisq.core.support.dispute.DisputeResult;
import bisq.core.trade.HavenoUtils;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
@ -108,9 +107,7 @@ public class GrpcDisputesService extends DisputesImplBase {
try { try {
var winner = ProtoUtil.enumFromProto(DisputeResult.Winner.class, req.getWinner().name()); var winner = ProtoUtil.enumFromProto(DisputeResult.Winner.class, req.getWinner().name());
var reason = ProtoUtil.enumFromProto(DisputeResult.Reason.class, req.getReason().name()); var reason = ProtoUtil.enumFromProto(DisputeResult.Reason.class, req.getReason().name());
// scale atomic unit to centineros for consistency TODO switch base to atomic units? coreApi.resolveDispute(req.getTradeId(), winner, reason, req.getSummaryNotes(), req.getCustomPayoutAmount());
var customPayoutAmount = HavenoUtils.atomicUnitsToCentineros(req.getCustomPayoutAmount());
coreApi.resolveDispute(req.getTradeId(), winner, reason, req.getSummaryNotes(), customPayoutAmount);
var reply = ResolveDisputeReply.newBuilder().build(); var reply = ResolveDisputeReply.newBuilder().build();
responseObserver.onNext(reply); responseObserver.onNext(reply);
responseObserver.onCompleted(); responseObserver.onCompleted();

View File

@ -21,7 +21,6 @@ import bisq.core.api.CoreApi;
import bisq.core.api.model.OfferInfo; import bisq.core.api.model.OfferInfo;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OpenOffer; import bisq.core.offer.OpenOffer;
import bisq.core.trade.HavenoUtils;
import bisq.proto.grpc.CancelOfferReply; import bisq.proto.grpc.CancelOfferReply;
import bisq.proto.grpc.CancelOfferRequest; import bisq.proto.grpc.CancelOfferRequest;
import bisq.proto.grpc.PostOfferReply; import bisq.proto.grpc.PostOfferReply;
@ -154,8 +153,8 @@ class GrpcOffersService extends OffersImplBase {
req.getPrice(), req.getPrice(),
req.getUseMarketBasedPrice(), req.getUseMarketBasedPrice(),
req.getMarketPriceMarginPct(), req.getMarketPriceMarginPct(),
HavenoUtils.atomicUnitsToCentineros(req.getAmount()), // scale atomic unit to centineros for consistency TODO switch base to atomic units? req.getAmount(),
HavenoUtils.atomicUnitsToCentineros(req.getMinAmount()), req.getMinAmount(),
req.getBuyerSecurityDepositPct(), req.getBuyerSecurityDepositPct(),
req.getTriggerPrice(), req.getTriggerPrice(),
req.getPaymentAccountId(), req.getPaymentAccountId(),

View File

@ -37,8 +37,6 @@ import bisq.proto.grpc.SendChatMessageReply;
import bisq.proto.grpc.SendChatMessageRequest; import bisq.proto.grpc.SendChatMessageRequest;
import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferReply;
import bisq.proto.grpc.TakeOfferRequest; import bisq.proto.grpc.TakeOfferRequest;
import bisq.proto.grpc.WithdrawFundsReply;
import bisq.proto.grpc.WithdrawFundsRequest;
import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver; 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 @Override
public void getChatMessages(GetChatMessagesRequest req, public void getChatMessages(GetChatMessagesRequest req,
StreamObserver<GetChatMessagesReply> responseObserver) { StreamObserver<GetChatMessagesReply> responseObserver) {

View File

@ -25,7 +25,7 @@ import bisq.desktop.util.GUIUtil;
import bisq.core.account.sign.SignedWitnessService; import bisq.core.account.sign.SignedWitnessService;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.offer.OfferRestrictions; import bisq.core.offer.OfferRestrictions;
import bisq.core.util.coin.CoinFormatter; import bisq.core.trade.HavenoUtils;
import bisq.common.UserThread; import bisq.common.UserThread;
@ -54,14 +54,13 @@ public class AccountStatusTooltipLabel extends AutoTooltipLabel {
private PopOver popOver; private PopOver popOver;
private boolean keepPopOverVisible = false; private boolean keepPopOverVisible = false;
public AccountStatusTooltipLabel(OfferBookListItem.WitnessAgeData witnessAgeData, public AccountStatusTooltipLabel(OfferBookListItem.WitnessAgeData witnessAgeData) {
CoinFormatter formatter) {
super(witnessAgeData.getDisplayString()); super(witnessAgeData.getDisplayString());
this.witnessAgeData = witnessAgeData; this.witnessAgeData = witnessAgeData;
this.textIcon = FormBuilder.getIcon(witnessAgeData.getIcon()); this.textIcon = FormBuilder.getIcon(witnessAgeData.getIcon());
this.popupTitle = witnessAgeData.isLimitLifted() this.popupTitle = witnessAgeData.isLimitLifted()
? Res.get("offerbook.timeSinceSigning.tooltip.accountLimitLifted") ? 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(); positionAndActivateIcon();
} }

View File

@ -21,11 +21,9 @@ import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.GUIUtil; import bisq.desktop.util.GUIUtil;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.trade.HavenoUtils;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon; import de.jensd.fx.fontawesome.AwesomeIcon;
@ -40,6 +38,7 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import java.math.BigInteger;
import java.net.URI; import java.net.URI;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -50,7 +49,7 @@ public class AddressTextField extends AnchorPane {
private final StringProperty address = new SimpleStringProperty(); private final StringProperty address = new SimpleStringProperty();
private final StringProperty paymentLabel = 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; private boolean wasPrimaryButtonDown;
@ -128,16 +127,16 @@ public class AddressTextField extends AnchorPane {
return address; return address;
} }
public Coin getAmountAsCoin() { public BigInteger getAmount() {
return amountAsCoin.get(); return amount.get();
} }
public ObjectProperty<Coin> amountAsCoinProperty() { public ObjectProperty<BigInteger> amountAsProperty() {
return amountAsCoin; return amount;
} }
public void setAmountAsCoin(Coin amountAsCoin) { public void setAmount(BigInteger amount) {
this.amountAsCoin.set(amountAsCoin); this.amount.set(amount);
} }
public String getPaymentLabel() { public String getPaymentLabel() {
@ -158,11 +157,11 @@ public class AddressTextField extends AnchorPane {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private String getBitcoinURI() { private String getBitcoinURI() {
if (amountAsCoin.get().isNegative()) { if (amount.get().compareTo(BigInteger.valueOf(0)) < 0) {
log.warn("Amount must not be negative"); 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()); paymentLabel.get());
} }
} }

View File

@ -17,10 +17,9 @@
package bisq.desktop.components; package bisq.desktop.components;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
import org.bitcoinj.core.Coin;
import com.jfoenix.controls.JFXTextField; import com.jfoenix.controls.JFXTextField;
import javafx.scene.effect.BlurType; import javafx.scene.effect.BlurType;
@ -29,17 +28,19 @@ import javafx.scene.effect.Effect;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import java.math.BigInteger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class BalanceTextField extends AnchorPane { public class BalanceTextField extends AnchorPane {
private Coin targetAmount; private BigInteger targetAmount;
private final JFXTextField textField; private final JFXTextField textField;
private final Effect fundedEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.GREEN, 4, 0.0, 0, 0); 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 final Effect notFundedEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.ORANGERED, 4, 0.0, 0, 0);
private CoinFormatter formatter; private CoinFormatter formatter;
@Nullable @Nullable
private Coin balance; private BigInteger balance;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -64,13 +65,13 @@ public class BalanceTextField extends AnchorPane {
this.formatter = formatter; this.formatter = formatter;
} }
public void setBalance(Coin balance) { public void setBalance(BigInteger balance) {
this.balance = balance; this.balance = balance;
updateBalance(balance); updateBalance(balance);
} }
public void setTargetAmount(Coin targetAmount) { public void setTargetAmount(BigInteger targetAmount) {
this.targetAmount = targetAmount; this.targetAmount = targetAmount;
if (this.balance != null) if (this.balance != null)
@ -81,9 +82,9 @@ public class BalanceTextField extends AnchorPane {
// Private methods // Private methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void updateBalance(Coin balance) { private void updateBalance(BigInteger balance) {
if (formatter != null) if (formatter != null)
textField.setText(formatter.formatCoinWithCode(balance)); textField.setText(HavenoUtils.formatToXmrWithCode(balance));
//TODO: replace with new validation logic //TODO: replace with new validation logic
// if (targetAmount != null) { // if (targetAmount != null) {

View File

@ -238,7 +238,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
Tuple2<Label, VBox> availableBalanceBox = getBalanceBox(Res.get("mainView.balance.available")); Tuple2<Label, VBox> availableBalanceBox = getBalanceBox(Res.get("mainView.balance.available"));
availableBalanceBox.first.textProperty().bind(model.getAvailableBalance()); availableBalanceBox.first.textProperty().bind(model.getAvailableBalance());
availableBalanceBox.first.setPrefWidth(100); availableBalanceBox.first.setPrefWidth(105);
availableBalanceBox.first.tooltipProperty().bind(new ObjectBinding<>() { availableBalanceBox.first.tooltipProperty().bind(new ObjectBinding<>() {
{ {
bind(model.getAvailableBalance()); bind(model.getAvailableBalance());

View File

@ -115,6 +115,7 @@ import bisq.core.payment.validation.TransferwiseValidator;
import bisq.core.payment.validation.USPostalMoneyOrderValidator; import bisq.core.payment.validation.USPostalMoneyOrderValidator;
import bisq.core.payment.validation.UpholdValidator; import bisq.core.payment.validation.UpholdValidator;
import bisq.core.payment.validation.WeChatPayValidator; import bisq.core.payment.validation.WeChatPayValidator;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
@ -123,8 +124,6 @@ import bisq.common.util.Tuple2;
import bisq.common.util.Tuple3; import bisq.common.util.Tuple3;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -142,6 +141,7 @@ import javafx.collections.ObservableList;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import java.math.BigInteger;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -257,9 +257,9 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void onSaveNewAccount(PaymentAccount paymentAccount) { private void onSaveNewAccount(PaymentAccount paymentAccount) {
Coin maxTradeLimitAsCoin = paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin("USD"); BigInteger maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimit("USD");
Coin maxTradeLimitSecondMonth = maxTradeLimitAsCoin.divide(2L); BigInteger maxTradeLimitSecondMonth = maxTradeLimit.divide(BigInteger.valueOf(2L));
Coin maxTradeLimitFirstMonth = maxTradeLimitAsCoin.divide(4L); BigInteger maxTradeLimitFirstMonth = maxTradeLimit.divide(BigInteger.valueOf(4L));
if (paymentAccount instanceof F2FAccount) { if (paymentAccount instanceof F2FAccount) {
new Popup().information(Res.get("payment.f2f.info")) new Popup().information(Res.get("payment.f2f.info"))
.width(700) .width(700)
@ -287,17 +287,17 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
} else { } else {
String limitsInfoKey = "payment.limits.info"; String limitsInfoKey = "payment.limits.info";
String initialLimit = formatter.formatCoinWithCode(maxTradeLimitFirstMonth); String initialLimit = HavenoUtils.formatToXmrWithCode(maxTradeLimitFirstMonth);
if (PaymentMethod.hasChargebackRisk(paymentAccount.getPaymentMethod(), paymentAccount.getTradeCurrencies())) { if (PaymentMethod.hasChargebackRisk(paymentAccount.getPaymentMethod(), paymentAccount.getTradeCurrencies())) {
limitsInfoKey = "payment.limits.info.withSigning"; 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, new Popup().information(Res.get(limitsInfoKey,
initialLimit, initialLimit,
formatter.formatCoinWithCode(maxTradeLimitSecondMonth), HavenoUtils.formatToXmrWithCode(maxTradeLimitSecondMonth),
formatter.formatCoinWithCode(maxTradeLimitAsCoin))) HavenoUtils.formatToXmrWithCode(maxTradeLimit)))
.width(700) .width(700)
.closeButtonText(Res.get("shared.cancel")) .closeButtonText(Res.get("shared.cancel"))
.actionButtonText(Res.get("shared.iUnderstand")) .actionButtonText(Res.get("shared.iUnderstand"))

View File

@ -37,14 +37,13 @@ import monero.daemon.model.MoneroTx;
import monero.wallet.model.MoneroTransferQuery; import monero.wallet.model.MoneroTransferQuery;
import monero.wallet.model.MoneroTxQuery; import monero.wallet.model.MoneroTxQuery;
import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroTxWallet;
import org.bitcoinj.core.Coin;
@Slf4j @Slf4j
class DepositListItem { class DepositListItem {
private final StringProperty balance = new SimpleStringProperty(); private final StringProperty balance = new SimpleStringProperty();
private final XmrAddressEntry addressEntry; private final XmrAddressEntry addressEntry;
private final XmrWalletService xmrWalletService; private final XmrWalletService xmrWalletService;
private Coin balanceAsCoin; private BigInteger balanceAsBI;
private String usage = "-"; private String usage = "-";
private XmrBalanceListener balanceListener; private XmrBalanceListener balanceListener;
private int numTxOutputs = 0; private int numTxOutputs = 0;
@ -66,15 +65,15 @@ class DepositListItem {
balanceListener = new XmrBalanceListener(addressEntry.getSubaddressIndex()) { balanceListener = new XmrBalanceListener(addressEntry.getSubaddressIndex()) {
@Override @Override
public void onBalanceChanged(BigInteger balance) { public void onBalanceChanged(BigInteger balance) {
DepositListItem.this.balanceAsCoin = HavenoUtils.atomicUnitsToCoin(balance); DepositListItem.this.balanceAsBI = balance;
DepositListItem.this.balance.set(formatter.formatCoin(balanceAsCoin)); DepositListItem.this.balance.set(HavenoUtils.formatToXmr(balanceAsBI));
updateUsage(addressEntry.getSubaddressIndex(), null); updateUsage(addressEntry.getSubaddressIndex(), null);
} }
}; };
xmrWalletService.addBalanceListener(balanceListener); xmrWalletService.addBalanceListener(balanceListener);
balanceAsCoin = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex()); balanceAsBI = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
balance.set(formatter.formatCoin(balanceAsCoin)); balance.set(HavenoUtils.formatToXmr(balanceAsBI));
updateUsage(addressEntry.getSubaddressIndex(), cachedTxs); updateUsage(addressEntry.getSubaddressIndex(), cachedTxs);
@ -124,8 +123,8 @@ class DepositListItem {
return balance.get(); return balance.get();
} }
public Coin getBalanceAsCoin() { public BigInteger getBalanceAsBI() {
return balanceAsCoin; return balanceAsBI;
} }
public int getNumTxOutputs() { public int getNumTxOutputs() {

View File

@ -157,7 +157,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
setConfidenceColumnCellFactory(); setConfidenceColumnCellFactory();
addressColumn.setComparator(Comparator.comparing(DepositListItem::getAddressString)); 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())); confirmationsColumn.setComparator(Comparator.comparingLong(o -> o.getNumConfirmationsSinceFirstUsed()));
usageColumn.setComparator(Comparator.comparingInt(DepositListItem::getNumTxOutputs)); usageColumn.setComparator(Comparator.comparingInt(DepositListItem::getNumTxOutputs));
tableView.getSortOrder().add(usageColumn); tableView.getSortOrder().add(usageColumn);
@ -237,7 +237,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
xmrWalletService.addBalanceListener(balanceListener); xmrWalletService.addBalanceListener(balanceListener);
amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> { amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> {
addressTextField.setAmountAsCoin(ParsingUtils.parseToCoin(t, formatter)); addressTextField.setAmount(HavenoUtils.parseXmr(t));
updateQRCode(); updateQRCode();
}); });
@ -306,7 +306,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
.forEach(e -> observableList.add(new DepositListItem(e, xmrWalletService, formatter, incomingTxs))); .forEach(e -> observableList.add(new DepositListItem(e, xmrWalletService, formatter, incomingTxs)));
} }
private Coin getAmountAsCoin() { private Coin getAmount() {
return ParsingUtils.parseToCoin(amountTextField.getText(), formatter); return ParsingUtils.parseToCoin(amountTextField.getText(), formatter);
} }
@ -314,7 +314,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
private String getPaymentUri() { private String getPaymentUri() {
return xmrWalletService.getWallet().getPaymentUri(new MoneroTxConfig() return xmrWalletService.getWallet().getPaymentUri(new MoneroTxConfig()
.setAddress(addressTextField.getAddress()) .setAddress(addressTextField.getAddress())
.setAmount(HavenoUtils.coinToAtomicUnits(getAmountAsCoin())) .setAmount(HavenoUtils.coinToAtomicUnits(getAmount()))
.setNote(paymentLabelString)); .setNote(paymentLabelString));
} }

View File

@ -51,8 +51,6 @@ public class TransactionListItemFactory {
TransactionsListItem create(MoneroTxWallet transaction, @Nullable TransactionAwareTradable tradable) { TransactionsListItem create(MoneroTxWallet transaction, @Nullable TransactionAwareTradable tradable) {
return new TransactionsListItem(transaction, return new TransactionsListItem(transaction,
xmrWalletService, xmrWalletService,
tradable, tradable);
formatter,
preferences.getIgnoreDustThreshold());
} }
} }

View File

@ -24,7 +24,6 @@ import bisq.core.offer.OpenOffer;
import bisq.core.trade.HavenoUtils; import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Tradable; import bisq.core.trade.Tradable;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.util.coin.CoinFormatter;
import bisq.desktop.components.indicator.TxConfidenceIndicator; import bisq.desktop.components.indicator.TxConfidenceIndicator;
import bisq.desktop.util.DisplayUtils; import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil; import bisq.desktop.util.GUIUtil;
@ -41,11 +40,9 @@ import monero.wallet.model.MoneroIncomingTransfer;
import monero.wallet.model.MoneroOutgoingTransfer; import monero.wallet.model.MoneroOutgoingTransfer;
import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroTxWallet;
import monero.wallet.model.MoneroWalletListener; import monero.wallet.model.MoneroWalletListener;
import org.bitcoinj.core.Coin;
@Slf4j @Slf4j
class TransactionsListItem { class TransactionsListItem {
private final CoinFormatter formatter;
private String dateString; private String dateString;
private final Date date; private final Date date;
private final String txId; private final String txId;
@ -56,11 +53,10 @@ class TransactionsListItem {
private String direction = ""; private String direction = "";
private boolean received; private boolean received;
private boolean detailsAvailable; private boolean detailsAvailable;
private Coin amountAsCoin = Coin.ZERO; private BigInteger amount = BigInteger.valueOf(0);
private String memo = ""; private String memo = "";
private long confirmations = 0; private long confirmations = 0;
@Getter @Getter
private final boolean isDustAttackTx;
private boolean initialTxConfidenceVisibility = true; private boolean initialTxConfidenceVisibility = true;
private final Supplier<LazyFields> lazyFieldsSupplier; private final Supplier<LazyFields> lazyFieldsSupplier;
@ -77,25 +73,20 @@ class TransactionsListItem {
TransactionsListItem() { TransactionsListItem() {
date = null; date = null;
txId = null; txId = null;
formatter = null;
isDustAttackTx = false;
lazyFieldsSupplier = null; lazyFieldsSupplier = null;
} }
TransactionsListItem(MoneroTxWallet tx, TransactionsListItem(MoneroTxWallet tx,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
TransactionAwareTradable transactionAwareTradable, TransactionAwareTradable transactionAwareTradable) {
CoinFormatter formatter,
long ignoreDustThreshold) {
this.formatter = formatter;
this.memo = tx.getNote(); this.memo = tx.getNote();
this.txId = tx.getHash(); this.txId = tx.getHash();
Optional<Tradable> optionalTradable = Optional.ofNullable(transactionAwareTradable) Optional<Tradable> optionalTradable = Optional.ofNullable(transactionAwareTradable)
.map(TransactionAwareTradable::asTradable); .map(TransactionAwareTradable::asTradable);
Coin valueSentToMe = HavenoUtils.atomicUnitsToCoin(tx.getIncomingAmount() == null ? new BigInteger("0") : tx.getIncomingAmount()); BigInteger valueSentToMe = tx.getIncomingAmount() == null ? new BigInteger("0") : tx.getIncomingAmount();
Coin valueSentFromMe = HavenoUtils.atomicUnitsToCoin(tx.getOutgoingAmount() == null ? new BigInteger("0") : tx.getOutgoingAmount()); BigInteger valueSentFromMe = tx.getOutgoingAmount() == null ? new BigInteger("0") : tx.getOutgoingAmount();
if (tx.getTransfers().get(0).isIncoming()) { if (tx.getTransfers().get(0).isIncoming()) {
addressString = ((MoneroIncomingTransfer) tx.getTransfers().get(0)).getAddress(); addressString = ((MoneroIncomingTransfer) tx.getTransfers().get(0)).getAddress();
@ -105,12 +96,12 @@ class TransactionsListItem {
else addressString = "unavailable"; else addressString = "unavailable";
} }
if (valueSentFromMe.isZero()) { if (valueSentFromMe.compareTo(BigInteger.valueOf(0)) == 0) {
amountAsCoin = valueSentToMe; amount = valueSentToMe;
direction = Res.get("funds.tx.direction.receivedWith"); direction = Res.get("funds.tx.direction.receivedWith");
received = true; received = true;
} else { } else {
amountAsCoin = valueSentFromMe.multiply(-1); amount = valueSentFromMe.multiply(BigInteger.valueOf(-1));
received = false; received = false;
direction = Res.get("funds.tx.direction.sentTo"); direction = Res.get("funds.tx.direction.sentTo");
} }
@ -134,13 +125,13 @@ class TransactionsListItem {
} else if (trade.getPayoutTxId() != null && } else if (trade.getPayoutTxId() != null &&
trade.getPayoutTxId().equals(txId)) { trade.getPayoutTxId().equals(txId)) {
details = Res.get("funds.tx.multiSigPayout", tradeId); details = Res.get("funds.tx.multiSigPayout", tradeId);
if (amountAsCoin.isZero()) { if (amount.compareTo(BigInteger.valueOf(0)) == 0) {
initialTxConfidenceVisibility = false; initialTxConfidenceVisibility = false;
} }
} else { } else {
Trade.DisputeState disputeState = trade.getDisputeState(); Trade.DisputeState disputeState = trade.getDisputeState();
if (disputeState == Trade.DisputeState.DISPUTE_CLOSED) { if (disputeState == Trade.DisputeState.DISPUTE_CLOSED) {
if (valueSentToMe.isPositive()) { if (valueSentToMe.compareTo(BigInteger.valueOf(0)) > 0) {
details = Res.get("funds.tx.disputePayout", tradeId); details = Res.get("funds.tx.disputePayout", tradeId);
} else { } else {
details = Res.get("funds.tx.disputeLost", tradeId); details = Res.get("funds.tx.disputeLost", tradeId);
@ -148,7 +139,7 @@ class TransactionsListItem {
} else if (disputeState == Trade.DisputeState.REFUND_REQUEST_CLOSED || } else if (disputeState == Trade.DisputeState.REFUND_REQUEST_CLOSED ||
disputeState == Trade.DisputeState.REFUND_REQUESTED || disputeState == Trade.DisputeState.REFUND_REQUESTED ||
disputeState == Trade.DisputeState.REFUND_REQUEST_STARTED_BY_PEER) { 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); details = Res.get("funds.tx.refund", tradeId);
} else { } else {
// We have spent the deposit tx outputs to the Bisq donation address to enable // 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. // 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 // 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. // 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); details = Res.get("funds.tx.collateralForRefund", tradeId);
initialTxConfidenceVisibility = false; initialTxConfidenceVisibility = false;
} }
@ -166,7 +157,7 @@ class TransactionsListItem {
} }
} }
} else { } else {
if (amountAsCoin.isZero()) { if (amount.compareTo(BigInteger.valueOf(0)) == 0) {
details = Res.get("funds.tx.noFundsFromDispute"); details = Res.get("funds.tx.noFundsFromDispute");
} }
} }
@ -176,11 +167,6 @@ class TransactionsListItem {
this.date = new Date(timestamp); this.date = new Date(timestamp);
dateString = DisplayUtils.formatDateTime(date); dateString = DisplayUtils.formatDateTime(date);
isDustAttackTx = received && valueSentToMe.value < ignoreDustThreshold;
if (isDustAttackTx) {
details = Res.get("funds.tx.dustAttackTx");
}
// confidence // confidence
lazyFieldsSupplier = Suppliers.memoize(() -> new LazyFields() {{ lazyFieldsSupplier = Suppliers.memoize(() -> new LazyFields() {{
txConfidenceIndicator = new TxConfidenceIndicator(); txConfidenceIndicator = new TxConfidenceIndicator();
@ -217,16 +203,14 @@ class TransactionsListItem {
return dateString; return dateString;
} }
public String getAmountStr() {
public String getAmount() { return HavenoUtils.formatToXmr(amount);
return formatter.formatCoin(amountAsCoin);
} }
public Coin getAmountAsCoin() { public BigInteger getAmount() {
return amountAsCoin; return amount;
} }
public String getAddressString() { public String getAddressString() {
return addressString; return addressString;
} }

View File

@ -24,7 +24,6 @@ import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.AutoTooltipLabel; import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.ExternalHyperlink; import bisq.desktop.components.ExternalHyperlink;
import bisq.desktop.components.HyperlinkWithIcon; 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.OfferDetailsWindow;
import bisq.desktop.main.overlays.windows.TradeDetailsWindow; import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
import bisq.desktop.util.GUIUtil; 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())); addressColumn.setComparator(Comparator.comparing(item -> item.getDirection() + item.getAddressString()));
transactionColumn.setComparator(Comparator.comparing(TransactionsListItem::getTxId)); 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())); confidenceColumn.setComparator(Comparator.comparingLong(item -> item.getNumConfirmations()));
memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo)); memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo));
@ -221,7 +220,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
columns[1] = item.getDetails(); columns[1] = item.getDetails();
columns[2] = item.getDirection() + " " + item.getAddressString(); columns[2] = item.getDirection() + " " + item.getAddressString();
columns[3] = item.getTxId(); columns[3] = item.getTxId();
columns[4] = item.getAmount(); columns[4] = item.getAmountStr();
columns[5] = item.getMemo() == null ? "" : item.getMemo(); columns[5] = item.getMemo() == null ? "" : item.getMemo();
columns[6] = String.valueOf(item.getNumConfirmations()); columns[6] = String.valueOf(item.getNumConfirmations());
return columns; return columns;
@ -319,15 +318,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails"))); hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
setGraphic(hyperlinkWithIcon); setGraphic(hyperlinkWithIcon);
// If details are available its a trade tx and we don't expect any dust attack tx // 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 { } else {
setGraphic(new AutoTooltipLabel(item.getDetails())); setGraphic(new AutoTooltipLabel(item.getDetails()));
} }
}
} else { } else {
setGraphic(null); setGraphic(null);
if (hyperlinkWithIcon != null) if (hyperlinkWithIcon != null)
@ -423,7 +416,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) { if (item != null && !empty) {
setGraphic(new AutoTooltipLabel(item.getAmount())); setGraphic(new AutoTooltipLabel(item.getAmountStr()));
} else { } else {
setGraphic(null); setGraphic(null);
} }

View File

@ -23,11 +23,9 @@ import bisq.core.btc.listeners.XmrBalanceListener;
import bisq.core.btc.model.XmrAddressEntry; import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.util.ParsingUtils; import bisq.core.trade.HavenoUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
import org.bitcoinj.core.Coin;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import java.math.BigInteger; import java.math.BigInteger;
@ -41,7 +39,7 @@ class WithdrawalListItem {
private final XmrAddressEntry addressEntry; private final XmrAddressEntry addressEntry;
private final XmrWalletService walletService; private final XmrWalletService walletService;
private final CoinFormatter formatter; private final CoinFormatter formatter;
private Coin balance; private BigInteger balance;
private final String addressString; private final String addressString;
@Setter @Setter
@Getter @Getter
@ -74,7 +72,7 @@ class WithdrawalListItem {
private void updateBalance() { private void updateBalance() {
balance = walletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex()); balance = walletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
if (balance != null) if (balance != null)
balanceLabel.setText(formatter.formatCoin(this.balance)); balanceLabel.setText(HavenoUtils.formatToXmr(this.balance));
} }
public final String getLabel() { public final String getLabel() {
@ -111,7 +109,7 @@ class WithdrawalListItem {
return balanceLabel; return balanceLabel;
} }
public Coin getBalance() { public BigInteger getBalance() {
return balance; return balance;
} }

View File

@ -35,18 +35,12 @@ import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.user.DontShowAgainLookup; 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.core.util.validation.BtcAddressValidator;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import bisq.common.util.Tuple2; import bisq.common.util.Tuple2;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import monero.wallet.model.MoneroTxConfig; import monero.wallet.model.MoneroTxConfig;
import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroTxWallet;
@ -78,9 +72,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
private final XmrWalletService xmrWalletService; private final XmrWalletService xmrWalletService;
private final TradeManager tradeManager; private final TradeManager tradeManager;
private final P2PService p2PService; private final P2PService p2PService;
private final CoinFormatter formatter;
private XmrBalanceListener balanceListener; private XmrBalanceListener balanceListener;
private Coin amountAsCoin = Coin.ZERO; private BigInteger amount = BigInteger.valueOf(0);
private ChangeListener<String> amountListener; private ChangeListener<String> amountListener;
private ChangeListener<Boolean> amountFocusListener; private ChangeListener<Boolean> amountFocusListener;
private int rowIndex = 0; private int rowIndex = 0;
@ -94,13 +87,11 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
TradeManager tradeManager, TradeManager tradeManager,
P2PService p2PService, P2PService p2PService,
WalletsSetup walletsSetup, WalletsSetup walletsSetup,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
BtcAddressValidator btcAddressValidator, BtcAddressValidator btcAddressValidator,
WalletPasswordWindow walletPasswordWindow) { WalletPasswordWindow walletPasswordWindow) {
this.xmrWalletService = xmrWalletService; this.xmrWalletService = xmrWalletService;
this.tradeManager = tradeManager; this.tradeManager = tradeManager;
this.p2PService = p2PService; this.p2PService = p2PService;
this.formatter = formatter;
} }
@Override @Override
@ -136,7 +127,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
amountListener = (observable, oldValue, newValue) -> { amountListener = (observable, oldValue, newValue) -> {
if (amountTextField.focusedProperty().get()) { if (amountTextField.focusedProperty().get()) {
try { try {
amountAsCoin = ParsingUtils.parseToCoin(amountTextField.getText(), formatter); amount = HavenoUtils.parseXmr(amountTextField.getText());
} catch (Throwable t) { } catch (Throwable t) {
log.error("Error at amountTextField input. " + t.toString()); log.error("Error at amountTextField input. " + t.toString());
} }
@ -144,8 +135,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
}; };
amountFocusListener = (observable, oldValue, newValue) -> { amountFocusListener = (observable, oldValue, newValue) -> {
if (oldValue && !newValue) { if (oldValue && !newValue) {
if (amountAsCoin.isPositive()) if (amount.compareTo(BigInteger.valueOf(0)) > 0)
amountTextField.setText(formatter.formatCoin(amountAsCoin)); amountTextField.setText(HavenoUtils.formatToXmr(amount));
else else
amountTextField.setText(""); amountTextField.setText("");
} }
@ -184,23 +175,23 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
final String withdrawToAddress = withdrawToTextField.getText(); final String withdrawToAddress = withdrawToTextField.getText();
// get receiver amount // get receiver amount
Coin receiverAmount = amountAsCoin; BigInteger receiverAmount = amount;
if (!receiverAmount.isPositive()) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow")); if (receiverAmount.compareTo(BigInteger.valueOf(0)) <= 0) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow"));
// create tx // create tx
MoneroTxWallet tx = xmrWalletService.getWallet().createTx(new MoneroTxConfig() MoneroTxWallet tx = xmrWalletService.getWallet().createTx(new MoneroTxConfig()
.setAccountIndex(0) .setAccountIndex(0)
.setAmount(HavenoUtils.coinToAtomicUnits(receiverAmount)) // TODO: rename to centinerosToAtomicUnits()? .setAmount(receiverAmount)
.setAddress(withdrawToAddress)); .setAddress(withdrawToAddress));
// create confirmation message // create confirmation message
Coin sendersAmount = receiverAmount; BigInteger sendersAmount = receiverAmount;
Coin fee = HavenoUtils.atomicUnitsToCoin(tx.getFee()); BigInteger fee = tx.getFee();
String messageText = Res.get("shared.sendFundsDetailsWithFee", String messageText = Res.get("shared.sendFundsDetailsWithFee",
formatter.formatCoinWithCode(sendersAmount), HavenoUtils.formatToXmrWithCode(sendersAmount),
withdrawToAddress, withdrawToAddress,
formatter.formatCoinWithCode(fee), HavenoUtils.formatToXmrWithCode(fee),
formatter.formatCoinWithCode(receiverAmount)); HavenoUtils.formatToXmrWithCode(receiverAmount));
// popup confirmation message // popup confirmation message
new Popup().headLine(Res.get("funds.withdrawal.confirmWithdrawalRequest")) 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 xmrWalletService.getWallet().setTxNote(tx.getHash(), withdrawMemoTextField.getText()); // TODO (monero-java): tx note does not persist when tx created then relayed
String key = "showTransactionSent"; String key = "showTransactionSent";
if (DontShowAgainLookup.showAgain(key)) { 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) .dontShowAgainId(key)
.show(); .show();
} }
@ -225,7 +216,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
.filter(Trade::isPayoutPublished) .filter(Trade::isPayoutPublished)
.forEach(trade -> xmrWalletService.getAddressEntry(trade.getId(), XmrAddressEntry.Context.TRADE_PAYOUT) .forEach(trade -> xmrWalletService.getAddressEntry(trade.getId(), XmrAddressEntry.Context.TRADE_PAYOUT)
.ifPresent(addressEntry -> { .ifPresent(addressEntry -> {
if (xmrWalletService.getBalanceForAddress(addressEntry.getAddressString()).isZero()) if (xmrWalletService.getBalanceForAddress(addressEntry.getAddressString()).compareTo(BigInteger.valueOf(0)) == 0)
tradeManager.onTradeCompleted(trade); tradeManager.onTradeCompleted(trade);
})); }));
} catch (Exception e) { } catch (Exception e) {
@ -251,7 +242,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void reset() { private void reset() {
amountAsCoin = Coin.ZERO; amount = BigInteger.valueOf(0);
amountTextField.setText(""); amountTextField.setText("");
amountTextField.setPromptText(Res.get("funds.withdrawal.setAmount")); amountTextField.setPromptText(Res.get("funds.withdrawal.setAmount"));

View File

@ -32,7 +32,6 @@ import bisq.desktop.util.CurrencyList;
import bisq.desktop.util.CurrencyListItem; import bisq.desktop.util.CurrencyListItem;
import bisq.desktop.util.DisplayUtils; import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil; import bisq.desktop.util.GUIUtil;
import bisq.common.UserThread;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.GlobalSettings; import bisq.core.locale.GlobalSettings;
@ -67,7 +66,6 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors; import java.util.stream.Collectors;
class OfferBookChartViewModel extends ActivatableViewModel { class OfferBookChartViewModel extends ActivatableViewModel {
@ -402,7 +400,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
for (Offer offer : sortedList) { for (Offer offer : sortedList) {
Price price = offer.getPrice(); Price price = offer.getPrice();
if (price != null) { 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; accumulatedAmount += amount;
offerTableListTemp.add(new OfferListItem(offer, accumulatedAmount)); offerTableListTemp.add(new OfferListItem(offer, accumulatedAmount));

View File

@ -19,11 +19,11 @@ package bisq.desktop.main.market.spread;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class SpreadItem { public class SpreadItem {
@ -36,10 +36,10 @@ public class SpreadItem {
public final Price priceSpread; public final Price priceSpread;
public final String percentage; public final String percentage;
public final double percentageValue; public final double percentageValue;
public final Coin totalAmount; public final BigInteger totalAmount;
public SpreadItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers, 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.currencyCode = currencyCode;
this.numberOfBuyOffers = numberOfBuyOffers; this.numberOfBuyOffers = numberOfBuyOffers;
this.numberOfSellOffers = numberOfSellOffers; this.numberOfSellOffers = numberOfSellOffers;

View File

@ -26,11 +26,10 @@ import bisq.desktop.util.GUIUtil;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -48,6 +47,7 @@ import javafx.collections.transformation.SortedList;
import javafx.util.Callback; import javafx.util.Callback;
import java.math.BigInteger;
import java.util.Comparator; import java.util.Comparator;
@FxmlView @FxmlView
@ -127,7 +127,10 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
int numberOfOffers = sortedList.stream().mapToInt(item -> item.numberOfOffers).sum(); int numberOfOffers = sortedList.stream().mapToInt(item -> item.numberOfOffers).sum();
int numberOfBuyOffers = sortedList.stream().mapToInt(item -> item.numberOfBuyOffers).sum(); int numberOfBuyOffers = sortedList.stream().mapToInt(item -> item.numberOfBuyOffers).sum();
int numberOfSellOffers = sortedList.stream().mapToInt(item -> item.numberOfSellOffers).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(() -> { UserThread.execute(() -> {
numberOfOffersColumn.setGraphic(new AutoTooltipLabel(Res.get("market.spread.numberOfOffersColumn", numberOfOffers))); numberOfOffersColumn.setGraphic(new AutoTooltipLabel(Res.get("market.spread.numberOfOffersColumn", numberOfOffers)));

View File

@ -30,10 +30,10 @@ import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection; import bisq.core.offer.OfferDirection;
import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -48,6 +48,7 @@ import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.ArrayList; import java.util.ArrayList;
@ -135,7 +136,7 @@ class SpreadViewModel extends ActivatableViewModel {
} }
spreadItems.clear(); spreadItems.clear();
Coin totalAmount = null; BigInteger totalAmount = BigInteger.valueOf(0);
for (String key : offersByCurrencyMap.keySet()) { for (String key : offersByCurrencyMap.keySet()) {
List<Offer> offers = offersByCurrencyMap.get(key); 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(), spreadItems.add(new SpreadItem(key, buyOffers.size(), sellOffers.size(),
uniqueOffers.size(), spread, percentage, percentageValue, totalAmount)); uniqueOffers.size(), spread, percentage, percentageValue, totalAmount));
} }
@ -243,11 +244,11 @@ class SpreadViewModel extends ActivatableViewModel {
maxPlacesForAmount.set(formatAmount(totalAmount, false).length()); maxPlacesForAmount.set(formatAmount(totalAmount, false).length());
} }
public String getAmount(Coin amount) { public String getAmount(BigInteger amount) {
return formatAmount(amount, true); return formatAmount(amount, true);
} }
private String formatAmount(Coin amount, boolean decimalAligned) { private String formatAmount(BigInteger amount, boolean decimalAligned) {
return formatter.formatCoin(amount, GUIUtil.AMOUNT_DECIMALS, decimalAligned, maxPlacesForAmount.get()); return formatter.formatCoin(HavenoUtils.atomicUnitsToCoin(amount), GUIUtil.AMOUNT_DECIMALS, decimalAligned, maxPlacesForAmount.get());
} }
} }

View File

@ -113,27 +113,26 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
protected TradeCurrency tradeCurrency; protected TradeCurrency tradeCurrency;
protected final StringProperty tradeCurrencyCode = new SimpleStringProperty(); protected final StringProperty tradeCurrencyCode = new SimpleStringProperty();
protected final BooleanProperty useMarketBasedPrice = new SimpleBooleanProperty(); protected final BooleanProperty useMarketBasedPrice = new SimpleBooleanProperty();
protected final ObjectProperty<Coin> amount = new SimpleObjectProperty<>(); protected final ObjectProperty<BigInteger> amount = new SimpleObjectProperty<>();
protected final ObjectProperty<Coin> minAmount = new SimpleObjectProperty<>(); protected final ObjectProperty<BigInteger> minAmount = new SimpleObjectProperty<>();
protected final ObjectProperty<Price> price = new SimpleObjectProperty<>(); protected final ObjectProperty<Price> price = new SimpleObjectProperty<>();
protected final ObjectProperty<Volume> volume = new SimpleObjectProperty<>(); protected final ObjectProperty<Volume> volume = new SimpleObjectProperty<>();
protected final ObjectProperty<Volume> minVolume = new SimpleObjectProperty<>(); protected final ObjectProperty<Volume> minVolume = new SimpleObjectProperty<>();
// Percentage value of buyer security deposit. E.g. 0.01 means 1% of trade amount // 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 final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
protected PaymentAccount paymentAccount; protected PaymentAccount paymentAccount;
boolean isTabSelected; boolean isTabSelected;
protected double marketPriceMargin = 0; protected double marketPriceMargin = 0;
private Coin txFeeFromFeeService = Coin.ZERO;
@Getter @Getter
private boolean marketPriceAvailable; private boolean marketPriceAvailable;
protected boolean allowAmountUpdate = true; protected boolean allowAmountUpdate = true;
private final TradeStatisticsManager tradeStatisticsManager; 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<Price>> isNonZeroPrice = (p) -> p.get() != null && !p.get().isZero();
private final Predicate<ObjectProperty<Volume>> isNonZeroVolume = (v) -> v.get() != null && !v.get().isZero(); private final Predicate<ObjectProperty<Volume>> isNonZeroVolume = (v) -> v.get() != null && !v.get().isZero();
@Getter @Getter
@ -176,7 +175,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
addressEntry = xmrWalletService.getOrCreateAddressEntry(offerId, XmrAddressEntry.Context.OFFER_FUNDING); addressEntry = xmrWalletService.getOrCreateAddressEntry(offerId, XmrAddressEntry.Context.OFFER_FUNDING);
useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice()); useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice());
buyerSecurityDeposit.set(Restrictions.getMinBuyerSecurityDepositAsPercent()); buyerSecurityDepositPct.set(Restrictions.getMinBuyerSecurityDepositAsPercent());
xmrBalanceListener = new XmrBalanceListener(getAddressEntry().getSubaddressIndex()) { xmrBalanceListener = new XmrBalanceListener(getAddressEntry().getSubaddressIndex()) {
@Override @Override
@ -295,10 +294,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
amount.get(), amount.get(),
minAmount.get(), minAmount.get(),
price.get(), price.get(),
txFeeFromFeeService, Coin.ZERO,
useMarketBasedPrice.get(), useMarketBasedPrice.get(),
marketPriceMargin, marketPriceMargin,
buyerSecurityDeposit.get(), buyerSecurityDepositPct.get(),
paymentAccount); paymentAccount);
} }
@ -319,7 +318,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
setSuggestedSecurityDeposit(getPaymentAccount()); setSuggestedSecurityDeposit(getPaymentAccount());
if (amount.get() != null && this.allowAmountUpdate) if (amount.get() != null && this.allowAmountUpdate)
this.amount.set(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 // Suggested deposit is double the trade range over the previous lock time period, bounded by min/max deposit
var suggestedSecurityDeposit = var suggestedSecurityDeposit =
Math.min(2 * (max - min) / max, Restrictions.getMaxBuyerSecurityDepositAsPercent()); Math.min(2 * (max - min) / max, Restrictions.getMaxBuyerSecurityDepositAsPercent());
buyerSecurityDeposit.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit)); buyerSecurityDepositPct.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit));
} catch (Throwable t) { } catch (Throwable t) {
log.error(t.toString()); log.error(t.toString());
buyerSecurityDeposit.set(minSecurityDeposit); buyerSecurityDepositPct.set(minSecurityDeposit);
} }
} }
@ -421,7 +420,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
boolean isMinAmountLessOrEqualAmount() { boolean isMinAmountLessOrEqualAmount() {
//noinspection SimplifiableIfStatement //noinspection SimplifiableIfStatement
if (minAmount.get() != null && amount.get() != null) if (minAmount.get() != null && amount.get() != null)
return !minAmount.get().isGreaterThan(amount.get()); return minAmount.get().compareTo(amount.get()) <= 0;
return true; 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()); Volume volumeByAmount = price.get().getVolumeByAmount(minAmount.get());
// For HalCash we want multiple of 10 EUR // For HalCash we want multiple of 10 EUR
@ -526,7 +525,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
void calculateAmount() { void calculateAmount() {
if (isNonZeroPrice.test(price) && isNonZeroVolume.test(volume) && allowAmountUpdate) { if (isNonZeroPrice.test(price) && isNonZeroVolume.test(volume) && allowAmountUpdate) {
try { 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()) if (isUsingHalCashAccount())
value = CoinUtil.getAdjustedAmountForHalCash(value, price.get(), getMaxTradeLimit()); value = CoinUtil.getAdjustedAmountForHalCash(value, price.get(), getMaxTradeLimit());
else if (CurrencyUtil.isFiatCurrency(tradeCurrencyCode.get())) 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 // 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. // 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 // 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) { if (direction != null && amount.get() != null && makerFee != null) {
Coin feeAndSecDeposit = getSecurityDeposit().add(makerFee); BigInteger feeAndSecDeposit = getSecurityDeposit().add(makerFee);
Coin total = isBuyOffer() ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get()); BigInteger total = isBuyOffer() ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get());
totalToPayAsCoin.set(total); totalToPay.set(total);
updateBalance(); updateBalance();
} }
} }
Coin getSecurityDeposit() { BigInteger getSecurityDeposit() {
return isBuyOffer() ? getBuyerSecurityDepositAsCoin() : getSellerSecurityDepositAsCoin(); return isBuyOffer() ? getBuyerSecurityDeposit() : getSellerSecurityDeposit();
} }
void swapTradeToSavings() { void swapTradeToSavings() {
@ -571,7 +570,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
protected abstract Set<PaymentAccount> getUserPaymentAccounts(); protected abstract Set<PaymentAccount> getUserPaymentAccounts();
protected void setAmount(Coin amount) { protected void setAmount(BigInteger amount) {
this.amount.set(amount); this.amount.set(amount);
} }
@ -584,18 +583,18 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
} }
protected void setBuyerSecurityDeposit(double value) { protected void setBuyerSecurityDeposit(double value) {
this.buyerSecurityDeposit.set(value); this.buyerSecurityDepositPct.set(value);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
protected ReadOnlyObjectProperty<Coin> getAmount() { protected ReadOnlyObjectProperty<BigInteger> getAmount() {
return amount; return amount;
} }
protected ReadOnlyObjectProperty<Coin> getMinAmount() { protected ReadOnlyObjectProperty<BigInteger> getMinAmount() {
return minAmount; return minAmount;
} }
@ -611,7 +610,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
return minVolume; return minVolume;
} }
protected void setMinAmount(Coin minAmount) { protected void setMinAmount(BigInteger minAmount) {
this.minAmount.set(minAmount); this.minAmount.set(minAmount);
} }
@ -635,46 +634,46 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
return useMarketBasedPrice; return useMarketBasedPrice;
} }
ReadOnlyDoubleProperty getBuyerSecurityDeposit() { ReadOnlyDoubleProperty getBuyerSecurityDepositPct() {
return buyerSecurityDeposit; return buyerSecurityDepositPct;
} }
protected Coin getBuyerSecurityDepositAsCoin() { protected BigInteger getBuyerSecurityDeposit() {
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(buyerSecurityDeposit.get(), amount.get()); BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(buyerSecurityDepositPct.get(), amount.get());
return getBoundedBuyerSecurityDepositAsCoin(percentOfAmountAsCoin); return getBoundedBuyerSecurityDeposit(percentOfAmount);
} }
private Coin getSellerSecurityDepositAsCoin() { private BigInteger getSellerSecurityDeposit() {
Coin amountAsCoin = this.amount.get(); BigInteger amount = this.amount.get();
if (amountAsCoin == null) if (amount == null)
amountAsCoin = Coin.ZERO; amount = BigInteger.valueOf(0);
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin( BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(
createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDeposit.get()), amountAsCoin); createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDepositPct.get()), amount);
return getBoundedSellerSecurityDepositAsCoin(percentOfAmountAsCoin); 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 // 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. // MinBuyerSecurityDeposit from Restrictions.
return Coin.valueOf(Math.max(Restrictions.getMinBuyerSecurityDepositAsCoin().value, value.value)); 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 // 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. // MinSellerSecurityDeposit from Restrictions.
return Coin.valueOf(Math.max(Restrictions.getMinSellerSecurityDepositAsCoin().value, value.value)); return Restrictions.getMinSellerSecurityDeposit().max(value);
} }
ReadOnlyObjectProperty<Coin> totalToPayAsCoinProperty() { ReadOnlyObjectProperty<BigInteger> totalToPayAsProperty() {
return totalToPayAsCoin; return totalToPay;
} }
public void setMarketPriceAvailable(boolean marketPriceAvailable) { public void setMarketPriceAvailable(boolean marketPriceAvailable) {
this.marketPriceAvailable = marketPriceAvailable; this.marketPriceAvailable = marketPriceAvailable;
} }
public Coin getMakerFee() { public BigInteger getMakerFee() {
return HavenoUtils.getMakerFee(amount.get()); return HavenoUtils.getMakerFee(amount.get());
} }
@ -684,7 +683,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
} }
public boolean isMinBuyerSecurityDeposit() { public boolean isMinBuyerSecurityDeposit() {
return !getBuyerSecurityDepositAsCoin().isGreaterThan(Restrictions.getMinBuyerSecurityDepositAsCoin()); return getBuyerSecurityDeposit().compareTo(Restrictions.getMinBuyerSecurityDeposit()) <= 0;
} }
public void setTriggerPrice(long triggerPrice) { public void setTriggerPrice(long triggerPrice) {

View File

@ -48,6 +48,7 @@ import bisq.core.offer.OfferDirection;
import bisq.core.payment.FasterPaymentsAccount; import bisq.core.payment.FasterPaymentsAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.HavenoUtils;
import bisq.core.user.DontShowAgainLookup; import bisq.core.user.DontShowAgainLookup;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
@ -58,8 +59,6 @@ import bisq.common.util.Tuple2;
import bisq.common.util.Tuple3; import bisq.common.util.Tuple3;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import net.glxn.qrgen.QRCode; import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType; import net.glxn.qrgen.image.ImageType;
@ -105,7 +104,7 @@ import javafx.util.StringConverter;
import java.net.URI; import java.net.URI;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -157,7 +156,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
buyerSecurityDepositFocusedListener, priceFocusedListener, placeOfferCompletedListener, buyerSecurityDepositFocusedListener, priceFocusedListener, placeOfferCompletedListener,
priceAsPercentageFocusedListener, getShowWalletFundedNotificationListener, priceAsPercentageFocusedListener, getShowWalletFundedNotificationListener,
isMinBuyerSecurityDepositListener, triggerPriceFocusedListener; isMinBuyerSecurityDepositListener, triggerPriceFocusedListener;
private ChangeListener<Coin> missingCoinListener; private ChangeListener<BigInteger> missingCoinListener;
private ChangeListener<String> tradeCurrencyCodeListener, errorMessageListener, private ChangeListener<String> tradeCurrencyCodeListener, errorMessageListener,
marketPriceMarginListener, volumeListener, buyerSecurityDepositInBTCListener; marketPriceMarginListener, volumeListener, buyerSecurityDepositInBTCListener;
private ChangeListener<Number> marketPriceAvailableListener; private ChangeListener<Number> marketPriceAvailableListener;
@ -248,7 +247,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
onPaymentAccountsComboBoxSelected(); onPaymentAccountsComboBoxSelected();
balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsCoinProperty().get()); balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsProperty().get());
updatePriceToggle(); updatePriceToggle();
Label popOverLabel = OfferViewUtil.createPopOverLabel(Res.get("createOffer.triggerPrice.tooltip")); 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 // called from parent as the view does not get notified when the tab is closed
public void onClose() { public void onClose() {
// we use model.placeOfferCompleted to not react on close which was triggered by a successful placeOffer // 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(); model.getDataModel().swapTradeToSavings();
} }
} }
@ -411,7 +410,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
triggerPriceVBox.setVisible(false); 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) // temporarily disabled due to high CPU usage (per issue #4649)
// waitingForFundsSpinner.play(); // waitingForFundsSpinner.play();
@ -550,7 +549,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
volumeTextField.textProperty().bindBidirectional(model.volume); volumeTextField.textProperty().bindBidirectional(model.volume);
volumeTextField.promptTextProperty().bind(model.volumePromptLabel); volumeTextField.promptTextProperty().bind(model.volumePromptLabel);
totalToPayTextField.textProperty().bind(model.totalToPay); totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.getDataModel().getMissingCoin()); addressTextField.amountAsProperty().bind(model.getDataModel().getMissingCoin());
buyerSecurityDepositInputTextField.textProperty().bindBidirectional(model.buyerSecurityDeposit); buyerSecurityDepositInputTextField.textProperty().bindBidirectional(model.buyerSecurityDeposit);
buyerSecurityDepositLabel.textProperty().bind(model.buyerSecurityDepositLabel); buyerSecurityDepositLabel.textProperty().bind(model.buyerSecurityDepositLabel);
tradeFeeInBtcLabel.textProperty().bind(model.tradeFeeInBtcWithFiat); tradeFeeInBtcLabel.textProperty().bind(model.tradeFeeInBtcWithFiat);
@ -598,7 +597,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
volumeTextField.textProperty().unbindBidirectional(model.volume); volumeTextField.textProperty().unbindBidirectional(model.volume);
volumeTextField.promptTextProperty().unbindBidirectional(model.volume); volumeTextField.promptTextProperty().unbindBidirectional(model.volume);
totalToPayTextField.textProperty().unbind(); totalToPayTextField.textProperty().unbind();
addressTextField.amountAsCoinProperty().unbind(); addressTextField.amountAsProperty().unbind();
buyerSecurityDepositInputTextField.textProperty().unbindBidirectional(model.buyerSecurityDeposit); buyerSecurityDepositInputTextField.textProperty().unbindBidirectional(model.buyerSecurityDeposit);
buyerSecurityDepositLabel.textProperty().unbind(); buyerSecurityDepositLabel.textProperty().unbind();
tradeFeeInBtcLabel.textProperty().unbind(); tradeFeeInBtcLabel.textProperty().unbind();
@ -736,7 +735,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
if (newValue) { if (newValue) {
Notification walletFundedNotification = new Notification() Notification walletFundedNotification = new Notification()
.headLine(Res.get("notification.walletUpdate.headline")) .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(); .autoClose();
walletFundedNotification.show(); walletFundedNotification.show();

View File

@ -41,7 +41,7 @@ import bisq.core.offer.OfferRestrictions;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; 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.FiatVolumeValidator;
import bisq.core.payment.validation.SecurityDepositValidator; import bisq.core.payment.validation.SecurityDepositValidator;
import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.MarketPrice;
@ -84,6 +84,7 @@ import javafx.beans.value.ChangeListener;
import javafx.util.Callback; import javafx.util.Callback;
import java.math.BigInteger;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -92,7 +93,7 @@ import static javafx.beans.binding.Bindings.createStringBinding;
@Slf4j @Slf4j
public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> extends ActivatableWithDataModel<M> { public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> extends ActivatableWithDataModel<M> {
private final BtcValidator btcValidator; private final XmrValidator xmrValidator;
protected final SecurityDepositValidator securityDepositValidator; protected final SecurityDepositValidator securityDepositValidator;
protected final PriceFeedService priceFeedService; protected final PriceFeedService priceFeedService;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
@ -163,8 +164,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private ChangeListener<String> volumeStringListener; private ChangeListener<String> volumeStringListener;
private ChangeListener<String> securityDepositStringListener; private ChangeListener<String> securityDepositStringListener;
private ChangeListener<Coin> amountAsCoinListener; private ChangeListener<BigInteger> amountListener;
private ChangeListener<Coin> minAmountAsCoinListener; private ChangeListener<BigInteger> minAmountListener;
private ChangeListener<Price> priceListener; private ChangeListener<Price> priceListener;
private ChangeListener<Volume> volumeListener; private ChangeListener<Volume> volumeListener;
private ChangeListener<Number> securityDepositAsDoubleListener; private ChangeListener<Number> securityDepositAsDoubleListener;
@ -190,7 +191,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
FiatVolumeValidator fiatVolumeValidator, FiatVolumeValidator fiatVolumeValidator,
FiatPriceValidator fiatPriceValidator, FiatPriceValidator fiatPriceValidator,
AltcoinValidator altcoinValidator, AltcoinValidator altcoinValidator,
BtcValidator btcValidator, XmrValidator btcValidator,
SecurityDepositValidator securityDepositValidator, SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
@ -203,7 +204,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
this.fiatVolumeValidator = fiatVolumeValidator; this.fiatVolumeValidator = fiatVolumeValidator;
this.fiatPriceValidator = fiatPriceValidator; this.fiatPriceValidator = fiatPriceValidator;
this.altcoinValidator = altcoinValidator; this.altcoinValidator = altcoinValidator;
this.btcValidator = btcValidator; this.xmrValidator = btcValidator;
this.securityDepositValidator = securityDepositValidator; this.securityDepositValidator = securityDepositValidator;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
@ -271,10 +272,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
() -> Res.get("createOffer.volume.prompt", dataModel.getTradeCurrencyCode().get()), () -> Res.get("createOffer.volume.prompt", dataModel.getTradeCurrencyCode().get()),
dataModel.getTradeCurrencyCode())); dataModel.getTradeCurrencyCode()));
totalToPay.bind(createStringBinding(() -> btcFormatter.formatCoinWithCode(dataModel.totalToPayAsCoinProperty().get()), totalToPay.bind(createStringBinding(() -> HavenoUtils.formatToXmrWithCode(dataModel.totalToPayAsProperty().get()),
dataModel.totalToPayAsCoinProperty())); dataModel.totalToPayAsProperty()));
tradeAmount.bind(createStringBinding(() -> btcFormatter.formatCoinWithCode(dataModel.getAmount().get()), tradeAmount.bind(createStringBinding(() -> HavenoUtils.formatToXmrWithCode(dataModel.getAmount().get()),
dataModel.getAmount())); dataModel.getAmount()));
tradeCurrencyCode.bind(dataModel.getTradeCurrencyCode()); tradeCurrencyCode.bind(dataModel.getTradeCurrencyCode());
@ -298,7 +299,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void createListeners() { private void createListeners() {
amountStringListener = (ov, oldValue, newValue) -> { amountStringListener = (ov, oldValue, newValue) -> {
if (!ignoreAmountStringListener) { if (!ignoreAmountStringListener) {
if (isBtcInputValid(newValue).isValid) { if (isXmrInputValid(newValue).isValid) {
setAmountToModel(); setAmountToModel();
dataModel.calculateVolume(); dataModel.calculateVolume();
dataModel.calculateTotalToPay(); dataModel.calculateTotalToPay();
@ -308,7 +309,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
} }
}; };
minAmountStringListener = (ov, oldValue, newValue) -> { minAmountStringListener = (ov, oldValue, newValue) -> {
if (isBtcInputValid(newValue).isValid) if (isXmrInputValid(newValue).isValid)
setMinAmountToModel(); setMinAmountToModel();
updateButtonDisableState(); updateButtonDisableState();
}; };
@ -431,10 +432,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
}; };
amountAsCoinListener = (ov, oldValue, newValue) -> { amountListener = (ov, oldValue, newValue) -> {
if (newValue != null) { if (newValue != null) {
amount.set(btcFormatter.formatCoin(newValue)); amount.set(HavenoUtils.formatToXmr(newValue));
buyerSecurityDepositInBTC.set(btcFormatter.formatCoinWithCode(dataModel.getBuyerSecurityDepositAsCoin())); buyerSecurityDepositInBTC.set(HavenoUtils.formatToXmrWithCode(dataModel.getBuyerSecurityDeposit()));
} else { } else {
amount.set(""); amount.set("");
buyerSecurityDepositInBTC.set(""); buyerSecurityDepositInBTC.set("");
@ -442,9 +443,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
applyMakerFee(); applyMakerFee();
}; };
minAmountAsCoinListener = (ov, oldValue, newValue) -> { minAmountListener = (ov, oldValue, newValue) -> {
if (newValue != null) if (newValue != null)
minAmount.set(btcFormatter.formatCoin(newValue)); minAmount.set(HavenoUtils.formatToXmr(newValue));
else else
minAmount.set(""); minAmount.set("");
}; };
@ -473,7 +474,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (newValue != null) { if (newValue != null) {
buyerSecurityDeposit.set(FormattingUtils.formatToPercent((double) newValue)); buyerSecurityDeposit.set(FormattingUtils.formatToPercent((double) newValue));
if (dataModel.getAmount().get() != null) { if (dataModel.getAmount().get() != null) {
buyerSecurityDepositInBTC.set(btcFormatter.formatCoinWithCode(dataModel.getBuyerSecurityDepositAsCoin())); buyerSecurityDepositInBTC.set(HavenoUtils.formatToXmrWithCode(dataModel.getBuyerSecurityDeposit()));
} }
updateBuyerSecurityDeposit(); updateBuyerSecurityDeposit();
} else { } else {
@ -498,13 +499,13 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
tradeFeeCurrencyCode.set(Res.getBaseCurrencyCode()); tradeFeeCurrencyCode.set(Res.getBaseCurrencyCode());
tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly")); tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly"));
Coin makerFeeAsCoin = dataModel.getMakerFee(); BigInteger makerFee = dataModel.getMakerFee();
if (makerFeeAsCoin == null) { if (makerFee == null) {
return; return;
} }
isTradeFeeVisible.setValue(true); isTradeFeeVisible.setValue(true);
tradeFee.set(getFormatterForMakerFee().formatCoin(makerFeeAsCoin)); tradeFee.set(HavenoUtils.formatToXmr(makerFee));
tradeFeeInBtcWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, tradeFeeInBtcWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
dataModel.getMakerFee(), dataModel.getMakerFee(),
btcFormatter)); btcFormatter));
@ -529,11 +530,11 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
buyerSecurityDeposit.addListener(securityDepositStringListener); buyerSecurityDeposit.addListener(securityDepositStringListener);
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding // Binding with Bindings.createObjectBinding does not work because of bi-directional binding
dataModel.getAmount().addListener(amountAsCoinListener); dataModel.getAmount().addListener(amountListener);
dataModel.getMinAmount().addListener(minAmountAsCoinListener); dataModel.getMinAmount().addListener(minAmountListener);
dataModel.getPrice().addListener(priceListener); dataModel.getPrice().addListener(priceListener);
dataModel.getVolume().addListener(volumeListener); dataModel.getVolume().addListener(volumeListener);
dataModel.getBuyerSecurityDeposit().addListener(securityDepositAsDoubleListener); dataModel.getBuyerSecurityDepositPct().addListener(securityDepositAsDoubleListener);
// dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener); // dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
dataModel.getIsXmrWalletFunded().addListener(isWalletFundedListener); dataModel.getIsXmrWalletFunded().addListener(isWalletFundedListener);
@ -551,11 +552,11 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
buyerSecurityDeposit.removeListener(securityDepositStringListener); buyerSecurityDeposit.removeListener(securityDepositStringListener);
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding // Binding with Bindings.createObjectBinding does not work because of bi-directional binding
dataModel.getAmount().removeListener(amountAsCoinListener); dataModel.getAmount().removeListener(amountListener);
dataModel.getMinAmount().removeListener(minAmountAsCoinListener); dataModel.getMinAmount().removeListener(minAmountListener);
dataModel.getPrice().removeListener(priceListener); dataModel.getPrice().removeListener(priceListener);
dataModel.getVolume().removeListener(volumeListener); dataModel.getVolume().removeListener(volumeListener);
dataModel.getBuyerSecurityDeposit().removeListener(securityDepositAsDoubleListener); dataModel.getBuyerSecurityDepositPct().removeListener(securityDepositAsDoubleListener);
//dataModel.feeFromFundingTxProperty.removeListener(feeFromFundingTxListener); //dataModel.feeFromFundingTxProperty.removeListener(feeFromFundingTxListener);
dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener); dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener);
@ -574,9 +575,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
boolean initWithData(OfferDirection direction, TradeCurrency tradeCurrency) { boolean initWithData(OfferDirection direction, TradeCurrency tradeCurrency) {
boolean result = dataModel.initWithData(direction, tradeCurrency); boolean result = dataModel.initWithData(direction, tradeCurrency);
if (dataModel.paymentAccount != null) if (dataModel.paymentAccount != null)
btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(dataModel.getTradeCurrencyCode().get())); xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
btcValidator.setMinValue(Restrictions.getMinTradeAmount()); xmrValidator.setMinValue(Restrictions.getMinTradeAmount());
final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY; final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY;
@ -592,7 +593,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
securityDepositValidator.setPaymentAccount(dataModel.paymentAccount); securityDepositValidator.setPaymentAccount(dataModel.paymentAccount);
validateAndSetBuyerSecurityDepositToModel(); validateAndSetBuyerSecurityDepositToModel();
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get())); buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
buyerSecurityDepositLabel.set(getSecurityDepositLabel()); buyerSecurityDepositLabel.set(getSecurityDepositLabel());
applyMakerFee(); applyMakerFee();
@ -630,10 +631,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
public void onPaymentAccountSelected(PaymentAccount paymentAccount) { public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
dataModel.onPaymentAccountSelected(paymentAccount); dataModel.onPaymentAccountSelected(paymentAccount);
if (amount.get() != null) if (amount.get() != null)
amountValidationResult.set(isBtcInputValid(amount.get())); amountValidationResult.set(isXmrInputValid(amount.get()));
btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(dataModel.getTradeCurrencyCode().get())); xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
maybeShowMakeOfferToUnsignedAccountWarning(); maybeShowMakeOfferToUnsignedAccountWarning();
securityDepositValidator.setPaymentAccount(paymentAccount); securityDepositValidator.setPaymentAccount(paymentAccount);
@ -659,8 +660,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
updateButtonDisableState(); updateButtonDisableState();
} else { } else {
new Popup().warning(Res.get("shared.notEnoughFunds", new Popup().warning(Res.get("shared.notEnoughFunds",
btcFormatter.formatCoinWithCode(dataModel.totalToPayAsCoinProperty().get()), HavenoUtils.formatToXmrWithCode(dataModel.totalToPayAsProperty().get()),
btcFormatter.formatCoinWithCode(dataModel.getTotalBalance()))) HavenoUtils.formatToXmrWithCode(dataModel.getTotalBalance())))
.actionButtonTextWithGoTo("navigation.funds.depositFunds") .actionButtonTextWithGoTo("navigation.funds.depositFunds")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class)) .onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
.show(); .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 // On focus out we do validation and apply the data to the model
void onFocusOutAmountTextField(boolean oldValue, boolean newValue) { void onFocusOutAmountTextField(boolean oldValue, boolean newValue) {
if (oldValue && !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); amountValidationResult.set(result);
System.out.println("Result is valid: " + result.isValid);
System.out.println("Result error: " + result.errorMessage);
if (result.isValid) { if (result.isValid) {
setAmountToModel(); setAmountToModel();
ignoreAmountStringListener = true; ignoreAmountStringListener = true;
amount.set(btcFormatter.formatCoin(dataModel.getAmount().get())); amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
ignoreAmountStringListener = false; ignoreAmountStringListener = false;
dataModel.calculateVolume(); dataModel.calculateVolume();
@ -690,12 +694,12 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
amountValidationResult.set(result); amountValidationResult.set(result);
if (minAmount.get() != null) if (minAmount.get() != null)
minAmountValidationResult.set(isBtcInputValid(minAmount.get())); minAmountValidationResult.set(isXmrInputValid(minAmount.get()));
} else if (amount.get() != null && btcValidator.getMaxTradeLimit() != null && btcValidator.getMaxTradeLimit().value == OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value) { } else if (amount.get() != null && xmrValidator.getMaxTradeLimit() != null && xmrValidator.getMaxTradeLimit().longValueExact() == OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact()) {
amount.set(btcFormatter.formatCoin(btcValidator.getMaxTradeLimit())); amount.set(HavenoUtils.formatToXmr(xmrValidator.getMaxTradeLimit()));
boolean isBuy = dataModel.getDirection() == OfferDirection.BUY; boolean isBuy = dataModel.getDirection() == OfferDirection.BUY;
new Popup().information(Res.get(isBuy ? "popup.warning.tradeLimitDueAccountAgeRestriction.buyer" : "popup.warning.tradeLimitDueAccountAgeRestriction.seller", 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"))) Res.get("offerbook.warning.newVersionAnnouncement")))
.width(900) .width(900)
.show(); .show();
@ -714,11 +718,11 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
public void onFocusOutMinAmountTextField(boolean oldValue, boolean newValue) { public void onFocusOutMinAmountTextField(boolean oldValue, boolean newValue) {
if (oldValue && !newValue) { if (oldValue && !newValue) {
InputValidator.ValidationResult result = isBtcInputValid(minAmount.get()); InputValidator.ValidationResult result = isXmrInputValid(minAmount.get());
minAmountValidationResult.set(result); minAmountValidationResult.set(result);
if (result.isValid) { if (result.isValid) {
Coin minAmountAsCoin = dataModel.getMinAmount().get(); BigInteger minAmount = dataModel.getMinAmount().get();
syncMinAmountWithAmount = minAmountAsCoin != null && minAmountAsCoin.equals(dataModel.getAmount().get()); syncMinAmountWithAmount = minAmount != null && minAmount.equals(dataModel.getAmount().get());
setMinAmountToModel(); setMinAmountToModel();
dataModel.calculateMinVolume(); dataModel.calculateMinVolume();
@ -732,14 +736,14 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
updateButtonDisableState(); updateButtonDisableState();
} }
this.minAmount.set(btcFormatter.formatCoin(minAmountAsCoin)); this.minAmount.set(HavenoUtils.formatToXmr(minAmount));
if (!dataModel.isMinAmountLessOrEqualAmount()) { if (!dataModel.isMinAmountLessOrEqualAmount()) {
this.amount.set(this.minAmount.get()); this.amount.set(this.minAmount.get());
} else { } else {
minAmountValidationResult.set(result); minAmountValidationResult.set(result);
if (this.amount.get() != null) if (this.amount.get() != null)
amountValidationResult.set(isBtcInputValid(this.amount.get())); amountValidationResult.set(isXmrInputValid(this.amount.get()));
} }
} else { } else {
syncMinAmountWithAmount = true; syncMinAmountWithAmount = true;
@ -864,12 +868,12 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
minAmount.set(amount.getValue()); minAmount.set(amount.getValue());
} else { } else {
if (amount.get() != null) 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 // We only check minAmountValidationResult if amountValidationResult is valid, otherwise we would get
// triggered a close of the popup when the minAmountValidationResult is applied // triggered a close of the popup when the minAmountValidationResult is applied
if (amountValidationResult.getValue() != null && amountValidationResult.getValue().isValid && minAmount.get() != null) 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(() -> { .onAction(() -> {
dataModel.setBuyerSecurityDeposit(defaultSecurityDeposit); dataModel.setBuyerSecurityDeposit(defaultSecurityDeposit);
ignoreSecurityDepositStringListener = true; ignoreSecurityDepositStringListener = true;
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get())); buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
ignoreSecurityDepositStringListener = false; ignoreSecurityDepositStringListener = false;
}) })
.closeButtonText(Res.get("createOffer.useLowerValue")) .closeButtonText(Res.get("createOffer.useLowerValue"))
@ -916,7 +920,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void applyBuyerSecurityDepositOnFocusOut() { private void applyBuyerSecurityDepositOnFocusOut() {
setBuyerSecurityDepositToModel(); setBuyerSecurityDepositToModel();
ignoreSecurityDepositStringListener = true; ignoreSecurityDepositStringListener = true;
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get())); buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
ignoreSecurityDepositStringListener = false; ignoreSecurityDepositStringListener = false;
} }
@ -985,12 +989,12 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
dataModel.getSecurityDeposit(), dataModel.getSecurityDeposit(),
dataModel.getAmount().get(), dataModel.getAmount().get(),
btcFormatter, btcFormatter,
Restrictions.getMinBuyerSecurityDepositAsCoin() Restrictions.getMinBuyerSecurityDeposit()
); );
} }
public String getSecurityDepositWithCode() { 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() { public String getMakerFeePercentage() {
final Coin makerFeeAsCoin = dataModel.getMakerFee(); final BigInteger makerFee = dataModel.getMakerFee();
return GUIUtil.getPercentage(makerFeeAsCoin, dataModel.getAmount().get()); return GUIUtil.getPercentage(makerFee, dataModel.getAmount().get());
} }
public String getTotalToPayInfo() { public String getTotalToPayInfo() {
return OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, return OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
dataModel.totalToPayAsCoin.get(), dataModel.totalToPay.get(),
btcFormatter); btcFormatter);
} }
@ -1083,7 +1087,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void setAmountToModel() { private void setAmountToModel() {
if (amount.get() != null && !amount.get().isEmpty()) { 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(); long maxTradeLimit = dataModel.getMaxTradeLimit();
Price price = dataModel.getPrice().get(); Price price = dataModel.getPrice().get();
@ -1107,7 +1111,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void setMinAmountToModel() { private void setMinAmountToModel() {
if (minAmount.get() != null && !minAmount.get().isEmpty()) { 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(); Price price = dataModel.getPrice().get();
long maxTradeLimit = dataModel.getMaxTradeLimit(); long maxTradeLimit = dataModel.getMaxTradeLimit();
@ -1158,7 +1162,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void validateAndSetBuyerSecurityDepositToModel() { private void validateAndSetBuyerSecurityDepositToModel() {
// If the security deposit in the model is not valid percent // 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) { if (!securityDepositValidator.validate(value).isValid) {
dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()); dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent());
} }
@ -1168,15 +1172,15 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (!makeOfferFromUnsignedAccountWarningDisplayed && if (!makeOfferFromUnsignedAccountWarningDisplayed &&
dataModel.getDirection() == OfferDirection.SELL && dataModel.getDirection() == OfferDirection.SELL &&
PaymentMethod.hasChargebackRisk(dataModel.getPaymentAccount().getPaymentMethod(), dataModel.getTradeCurrency().getCode())) { PaymentMethod.hasChargebackRisk(dataModel.getPaymentAccount().getPaymentMethod(), dataModel.getTradeCurrency().getCode())) {
Coin checkAmount = dataModel.getMinAmount().get() == null ? dataModel.getAmount().get() : dataModel.getMinAmount().get(); BigInteger checkAmount = dataModel.getMinAmount().get() == null ? dataModel.getAmount().get() : dataModel.getMinAmount().get();
if (checkAmount != null && !checkAmount.isGreaterThan(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT)) { if (checkAmount != null && checkAmount.compareTo(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT) <= 0) {
makeOfferFromUnsignedAccountWarningDisplayed = true; makeOfferFromUnsignedAccountWarningDisplayed = true;
} }
} }
} }
private InputValidator.ValidationResult isBtcInputValid(String input) { private InputValidator.ValidationResult isXmrInputValid(String input) {
return btcValidator.validate(input); return xmrValidator.validate("" + HavenoUtils.atomicUnitsToXmr(HavenoUtils.parseXmr(input)));
} }
private InputValidator.ValidationResult isPriceInputValid(String input) { private InputValidator.ValidationResult isPriceInputValid(String input) {
@ -1219,16 +1223,16 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (dataModel.isMinBuyerSecurityDeposit()) { if (dataModel.isMinBuyerSecurityDeposit()) {
buyerSecurityDepositLabel.set(Res.get("createOffer.minSecurityDepositUsed")); buyerSecurityDepositLabel.set(Res.get("createOffer.minSecurityDepositUsed"));
buyerSecurityDeposit.set(btcFormatter.formatCoin(Restrictions.getMinBuyerSecurityDepositAsCoin())); buyerSecurityDeposit.set(HavenoUtils.formatToXmr(Restrictions.getMinBuyerSecurityDeposit()));
} else { } else {
buyerSecurityDepositLabel.set(getSecurityDepositLabel()); buyerSecurityDepositLabel.set(getSecurityDepositLabel());
buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get())); buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()));
} }
} }
void updateButtonDisableState() { void updateButtonDisableState() {
boolean inputDataValid = isBtcInputValid(amount.get()).isValid && boolean inputDataValid = isXmrInputValid(amount.get()).isValid &&
isBtcInputValid(minAmount.get()).isValid && isXmrInputValid(minAmount.get()).isValid &&
isPriceInputValid(price.get()).isValid && isPriceInputValid(price.get()).isValid &&
dataModel.getPrice().get() != null && dataModel.getPrice().get() != null &&
dataModel.getPrice().get().getValue() != 0 && dataModel.getPrice().get().getValue() != 0 &&
@ -1249,10 +1253,6 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || !dataModel.getIsXmrWalletFunded().get()); isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || !dataModel.getIsXmrWalletFunded().get());
} }
private CoinFormatter getFormatterForMakerFee() {
return btcFormatter;
}
private void updateMarketPriceToManual() { private void updateMarketPriceToManual() {
final String currencyCode = dataModel.getTradeCurrencyCode().get(); final String currencyCode = dataModel.getTradeCurrencyCode().get();
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);

View File

@ -23,8 +23,6 @@ import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import org.bitcoinj.core.Coin;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
@ -32,7 +30,7 @@ import javafx.beans.property.SimpleObjectProperty;
import lombok.Getter; import lombok.Getter;
import static bisq.core.util.coin.CoinUtil.minCoin; import java.math.BigInteger;
/** /**
* Domain for that UI element. * Domain for that UI element.
@ -48,19 +46,19 @@ public abstract class OfferDataModel extends ActivatableDataModel {
@Getter @Getter
protected final BooleanProperty isXmrWalletFunded = new SimpleBooleanProperty(); protected final BooleanProperty isXmrWalletFunded = new SimpleBooleanProperty();
@Getter @Getter
protected final ObjectProperty<Coin> totalToPayAsCoin = new SimpleObjectProperty<>(); protected final ObjectProperty<BigInteger> totalToPay = new SimpleObjectProperty<>();
@Getter @Getter
protected final ObjectProperty<Coin> balance = new SimpleObjectProperty<>(); protected final ObjectProperty<BigInteger> balance = new SimpleObjectProperty<>();
@Getter @Getter
protected final ObjectProperty<Coin> availableBalance = new SimpleObjectProperty<>(); protected final ObjectProperty<BigInteger> availableBalance = new SimpleObjectProperty<>();
@Getter @Getter
protected final ObjectProperty<Coin> missingCoin = new SimpleObjectProperty<>(Coin.ZERO); protected final ObjectProperty<BigInteger> missingCoin = new SimpleObjectProperty<>(BigInteger.valueOf(0));
@Getter @Getter
protected final BooleanProperty showWalletFundedNotification = new SimpleBooleanProperty(); protected final BooleanProperty showWalletFundedNotification = new SimpleBooleanProperty();
@Getter @Getter
protected Coin totalBalance; protected BigInteger totalBalance;
@Getter @Getter
protected Coin totalAvailableBalance; protected BigInteger totalAvailableBalance;
protected XmrAddressEntry addressEntry; protected XmrAddressEntry addressEntry;
protected boolean useSavingsWallet; protected boolean useSavingsWallet;
@ -70,37 +68,37 @@ public abstract class OfferDataModel extends ActivatableDataModel {
} }
protected void updateBalance() { protected void updateBalance() {
Coin tradeWalletBalance = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex()); BigInteger tradeWalletBalance = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
if (useSavingsWallet) { if (useSavingsWallet) {
Coin walletBalance = xmrWalletService.getBalance(); BigInteger walletBalance = xmrWalletService.getBalance();
totalBalance = walletBalance.add(tradeWalletBalance); totalBalance = walletBalance.add(tradeWalletBalance);
if (totalToPayAsCoin.get() != null) { if (totalToPay.get() != null) {
balance.set(minCoin(totalToPayAsCoin.get(), totalBalance)); balance.set(totalToPay.get().min(totalBalance));
} }
} else { } else {
balance.set(tradeWalletBalance); balance.set(tradeWalletBalance);
} }
missingCoin.set(offerUtil.getBalanceShortage(totalToPayAsCoin.get(), balance.get())); missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), balance.get()));
isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPayAsCoin.get(), balance.get())); isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), balance.get()));
if (totalToPayAsCoin.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) { if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) {
showWalletFundedNotification.set(true); showWalletFundedNotification.set(true);
} }
} }
protected void updateAvailableBalance() { protected void updateAvailableBalance() {
Coin tradeWalletBalance = xmrWalletService.getAvailableBalanceForSubaddress(addressEntry.getSubaddressIndex()); BigInteger tradeWalletBalance = xmrWalletService.getAvailableBalanceForSubaddress(addressEntry.getSubaddressIndex());
if (useSavingsWallet) { if (useSavingsWallet) {
Coin walletAvailableBalance = xmrWalletService.getAvailableBalance(); BigInteger walletAvailableBalance = xmrWalletService.getAvailableBalance();
totalAvailableBalance = walletAvailableBalance.add(tradeWalletBalance); totalAvailableBalance = walletAvailableBalance.add(tradeWalletBalance);
if (totalToPayAsCoin.get() != null) { if (totalToPay.get() != null) {
availableBalance.set(minCoin(totalToPayAsCoin.get(), totalAvailableBalance)); availableBalance.set(totalToPay.get().min(totalAvailableBalance));
} }
} else { } else {
availableBalance.set(tradeWalletBalance); availableBalance.set(tradeWalletBalance);
} }
missingCoin.set(offerUtil.getBalanceShortage(totalToPayAsCoin.get(), availableBalance.get())); missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), availableBalance.get()));
isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPayAsCoin.get(), availableBalance.get())); isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), availableBalance.get()));
if (totalToPayAsCoin.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) { if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) {
showWalletFundedNotification.set(true); showWalletFundedNotification.set(true);
} }
} }

View File

@ -23,19 +23,17 @@ import bisq.desktop.util.GUIUtil;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.monetary.Volume; import bisq.core.monetary.Volume;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.VolumeUtil; import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
import bisq.common.app.DevEnv; import java.math.BigInteger;
import org.bitcoinj.core.Coin;
import java.util.Optional; import java.util.Optional;
// Shared utils for ViewModels // Shared utils for ViewModels
public class OfferViewModelUtil { public class OfferViewModelUtil {
public static String getTradeFeeWithFiatEquivalent(OfferUtil offerUtil, public static String getTradeFeeWithFiatEquivalent(OfferUtil offerUtil,
Coin tradeFee, BigInteger tradeFee,
CoinFormatter formatter) { CoinFormatter formatter) {
Optional<Volume> optionalBtcFeeInFiat = offerUtil.getFeeInUserFiatCurrency(tradeFee, Optional<Volume> optionalBtcFeeInFiat = offerUtil.getFeeInUserFiatCurrency(tradeFee,
@ -45,13 +43,13 @@ public class OfferViewModelUtil {
} }
public static String getTradeFeeWithFiatEquivalentAndPercentage(OfferUtil offerUtil, public static String getTradeFeeWithFiatEquivalentAndPercentage(OfferUtil offerUtil,
Coin tradeFee, BigInteger tradeFee,
Coin tradeAmount, BigInteger tradeAmount,
CoinFormatter formatter, CoinFormatter formatter,
Coin minTradeFee) { BigInteger minTradeFee) {
String feeAsBtc = formatter.formatCoinWithCode(tradeFee); String feeAsBtc = HavenoUtils.formatToXmrWithCode(tradeFee);
String percentage; String percentage;
if (!tradeFee.isGreaterThan(minTradeFee)) { if (tradeFee.compareTo(minTradeFee) <= 0) {
percentage = Res.get("guiUtil.requiredMinimum") percentage = Res.get("guiUtil.requiredMinimum")
.replace("(", "") .replace("(", "")
.replace(")", ""); .replace(")", "");

View File

@ -22,7 +22,7 @@ import bisq.desktop.common.model.ViewModel;
import bisq.desktop.main.offer.MutableOfferViewModel; import bisq.desktop.main.offer.MutableOfferViewModel;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.offer.OfferUtil; 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.FiatVolumeValidator;
import bisq.core.payment.validation.SecurityDepositValidator; import bisq.core.payment.validation.SecurityDepositValidator;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
@ -42,7 +42,7 @@ class CreateOfferViewModel extends MutableOfferViewModel<CreateOfferDataModel> i
FiatVolumeValidator fiatVolumeValidator, FiatVolumeValidator fiatVolumeValidator,
FiatPriceValidator fiatPriceValidator, FiatPriceValidator fiatPriceValidator,
AltcoinValidator altcoinValidator, AltcoinValidator altcoinValidator,
BtcValidator btcValidator, XmrValidator btcValidator,
SecurityDepositValidator securityDepositValidator, SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,

View File

@ -61,6 +61,7 @@ import bisq.core.offer.OfferRestrictions;
import bisq.core.offer.OpenOffer; import bisq.core.offer.OpenOffer;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.HavenoUtils;
import bisq.core.user.DontShowAgainLookup; import bisq.core.user.DontShowAgainLookup;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
@ -110,6 +111,8 @@ import javafx.collections.ListChangeListener;
import javafx.util.Callback; import javafx.util.Callback;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Comparator; import java.util.Comparator;
import java.util.Map; import java.util.Map;
import java.util.Optional; 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()))); avatarColumn.setComparator(Comparator.comparing(o -> model.getNumTrades(o.getOffer())));
depositColumn.setComparator(Comparator.comparing(item -> { depositColumn.setComparator(Comparator.comparing(item -> {
boolean isSellOffer = item.getOffer().getDirection() == OfferDirection.SELL; boolean isSellOffer = item.getOffer().getDirection() == OfferDirection.SELL;
Coin deposit = isSellOffer ? BigInteger deposit = isSellOffer ?
item.getOffer().getBuyerSecurityDeposit() : item.getOffer().getBuyerSecurityDeposit() :
item.getOffer().getSellerSecurityDeposit(); item.getOffer().getSellerSecurityDeposit();
double amountValue = item.getOffer().getAmount().getValue(); long amountValue = item.getOffer().getAmount().longValueExact();
if ((deposit == null || amountValue == 0)) { if ((deposit == null || amountValue == 0)) {
return 0d; return 0d;
} else { } else {
return deposit.getValue() / amountValue; return BigDecimal.valueOf(deposit.longValueExact()).divide(BigDecimal.valueOf(amountValue)).doubleValue();
} }
}, Comparator.nullsFirst(Comparator.naturalOrder()))); }, Comparator.nullsFirst(Comparator.naturalOrder())));
@ -715,7 +718,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
if (model.isBootstrappedOrShowPopup()) { if (model.isBootstrappedOrShowPopup()) {
String key = "RemoveOfferWarning"; String key = "RemoveOfferWarning";
if (DontShowAgainLookup.showAgain(key)) { 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.removeOffer", model.getMakerFeeAsString(offer)) :
Res.get("popup.warning.removeNoFeeOffer"); Res.get("popup.warning.removeNoFeeOffer");
new Popup().warning(message) new Popup().warning(message)
@ -1034,7 +1037,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
} else { } else {
setText(""); setText("");
setGraphic(new ColoredDecimalPlacesWithZerosText(model.formatDepositString( setGraphic(new ColoredDecimalPlacesWithZerosText(model.formatDepositString(
deposit, item.getOffer().getAmount().getValue()), deposit, item.getOffer().getAmount().longValueExact()),
GUIUtil.AMOUNT_DECIMALS_WITH_ZEROS)); GUIUtil.AMOUNT_DECIMALS_WITH_ZEROS));
} }
} else { } else {
@ -1186,7 +1189,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
Res.get("offerbook.timeSinceSigning"), Res.get("offerbook.timeSinceSigning"),
Res.get("offerbook.timeSinceSigning.help", Res.get("offerbook.timeSinceSigning.help",
SignedWitnessService.SIGNER_AGE_DAYS, SignedWitnessService.SIGNER_AGE_DAYS,
formatter.formatCoinWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT))) { HavenoUtils.formatToXmrWithCode(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT))) {
{ {
setMinWidth(60); setMinWidth(60);
setSortable(true); setSortable(true);
@ -1206,7 +1209,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
if (item != null && !empty) { if (item != null && !empty) {
var witnessAgeData = item.getWitnessAgeData(accountAgeWitnessService, signedWitnessService); var witnessAgeData = item.getWitnessAgeData(accountAgeWitnessService, signedWitnessService);
var label = witnessAgeData.isSigningRequired() var label = witnessAgeData.isSigningRequired()
? new AccountStatusTooltipLabel(witnessAgeData, formatter) ? new AccountStatusTooltipLabel(witnessAgeData)
: new InfoAutoTooltipLabel(witnessAgeData.getDisplayString(), witnessAgeData.getIcon(), ContentDisplay.RIGHT, witnessAgeData.getInfo()); : new InfoAutoTooltipLabel(witnessAgeData.getDisplayString(), witnessAgeData.getIcon(), ContentDisplay.RIGHT, witnessAgeData.getInfo());
setGraphic(label); setGraphic(label);
} else { } else {

View File

@ -47,6 +47,7 @@ import bisq.core.payment.PaymentAccountUtil;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.ClosedTradableManager; import bisq.core.trade.ClosedTradableManager;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.user.User; import bisq.core.user.User;
@ -61,8 +62,6 @@ import bisq.network.p2p.P2PService;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
import org.bitcoinj.core.Coin;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
@ -78,6 +77,8 @@ import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList; import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList; import javafx.collections.transformation.SortedList;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Comparator; import java.util.Comparator;
@ -181,7 +182,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
filterItemsListener = c -> { filterItemsListener = c -> {
final Optional<OfferBookListItem> highestAmountOffer = filteredItems.stream() 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()); 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()); maxPlacesForAmount.set(formatAmount(item.getOffer(), false).length());
maxPlacesForVolume.set(formatVolume(item.getOffer(), false).length()); maxPlacesForVolume.set(formatVolume(item.getOffer(), false).length());
} }
} }
final Optional<OfferBookListItem> highestPriceOffer = filteredItems.stream() final Optional<OfferBookListItem> highestPriceOffer = filteredItems.stream()
@ -627,7 +627,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
} }
public String getMakerFeeAsString(Offer offer) { public String getMakerFeeAsString(Offer offer) {
return btcFormatter.formatCoinWithCode(offer.getMakerFee()); return HavenoUtils.formatToXmrWithCode(offer.getMakerFee());
} }
private static String getDirectionWithCodeDetailed(OfferDirection direction, String currencyCode) { 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); return (direction == OfferDirection.SELL) ? Res.get("shared.buyingCurrency", currencyCode) : Res.get("shared.sellingCurrency", currencyCode);
} }
public String formatDepositString(Coin deposit, long amount) { public String formatDepositString(BigInteger deposit, long amount) {
var percentage = FormattingUtils.formatToRoundedPercentWithSymbol(deposit.getValue() / (double) amount); var percentage = FormattingUtils.formatToRoundedPercentWithSymbol(BigDecimal.valueOf(deposit.longValueExact()).divide(BigDecimal.valueOf(amount)).doubleValue());
return btcFormatter.formatCoin(deposit) + " (" + percentage + ")"; return HavenoUtils.formatToXmr(deposit) + " (" + percentage + ")";
} }
PaymentMethod getShowAllEntryForPaymentMethod() { PaymentMethod getShowAllEntryForPaymentMethod() {

View File

@ -26,7 +26,6 @@ import bisq.common.handlers.ErrorMessageHandler;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.listeners.XmrBalanceListener; import bisq.core.btc.listeners.XmrBalanceListener;
import bisq.core.btc.model.XmrAddressEntry; import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.btc.wallet.Restrictions;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.filter.FilterManager; import bisq.core.filter.FilterManager;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
@ -47,12 +46,9 @@ import bisq.core.trade.handlers.TradeResultHandler;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.user.User; import bisq.core.user.User;
import bisq.core.util.VolumeUtil; import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinUtil;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import org.bitcoinj.core.Coin;
import com.google.inject.Inject; import com.google.inject.Inject;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
@ -94,13 +90,13 @@ class TakeOfferDataModel extends OfferDataModel {
private final Navigation navigation; private final Navigation navigation;
private final P2PService p2PService; private final P2PService p2PService;
private Coin securityDeposit; private BigInteger securityDeposit;
private Offer offer; private Offer offer;
// final BooleanProperty isFeeFromFundingTxSufficient = new SimpleBooleanProperty(); // final BooleanProperty isFeeFromFundingTxSufficient = new SimpleBooleanProperty();
// final BooleanProperty isMainNet = 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<>(); final ObjectProperty<Volume> volume = new SimpleObjectProperty<>();
private XmrBalanceListener balanceListener; private XmrBalanceListener balanceListener;
@ -198,7 +194,7 @@ class TakeOfferDataModel extends OfferDataModel {
checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()"); checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()");
paymentAccount = getLastSelectedPaymentAccount(); 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 ? securityDeposit = offer.getDirection() == OfferDirection.SELL ?
getBuyerSecurityDeposit() : getBuyerSecurityDeposit() :
@ -263,7 +259,7 @@ class TakeOfferDataModel extends OfferDataModel {
void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) {
checkNotNull(getTakerFee(), "takerFee must not be null"); checkNotNull(getTakerFee(), "takerFee must not be null");
Coin fundsNeededForTrade = getFundsNeededForTrade(); BigInteger fundsNeededForTrade = getFundsNeededForTrade();
if (isBuyOffer()) if (isBuyOffer())
fundsNeededForTrade = fundsNeededForTrade.add(amount.get()); fundsNeededForTrade = fundsNeededForTrade.add(amount.get());
@ -301,7 +297,7 @@ class TakeOfferDataModel extends OfferDataModel {
this.paymentAccount = paymentAccount; this.paymentAccount = paymentAccount;
long myLimit = getMaxTradeLimit(); 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()); preferences.setTakeOfferSelectedPaymentAccountId(paymentAccount.getId());
} }
@ -385,7 +381,7 @@ class TakeOfferDataModel extends OfferDataModel {
void calculateVolume() { void calculateVolume() {
if (tradePrice != null && offer != null && if (tradePrice != null && offer != null &&
amount.get() != null && amount.get() != null &&
!amount.get().isZero()) { amount.get().compareTo(BigInteger.valueOf(0)) != 0) {
Volume volumeByAmount = tradePrice.getVolumeByAmount(amount.get()); Volume volumeByAmount = tradePrice.getVolumeByAmount(amount.get());
if (offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) if (offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID))
volumeByAmount = VolumeUtil.getAdjustedVolumeForHalCash(volumeByAmount); volumeByAmount = VolumeUtil.getAdjustedVolumeForHalCash(volumeByAmount);
@ -398,8 +394,8 @@ class TakeOfferDataModel extends OfferDataModel {
} }
} }
void applyAmount(Coin amount) { void applyAmount(BigInteger amount) {
this.amount.set(Coin.valueOf(Math.min(amount.value, getMaxTradeLimit()))); this.amount.set(amount.min(BigInteger.valueOf(getMaxTradeLimit())));
calculateTotalToPay(); 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 // 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. // 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 // 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) { if (offer != null && amount.get() != null && takerFee != null) {
Coin feeAndSecDeposit = securityDeposit.add(takerFee); BigInteger feeAndSecDeposit = securityDeposit.add(takerFee);
if (isBuyOffer()) if (isBuyOffer())
totalToPayAsCoin.set(feeAndSecDeposit.add(amount.get())); totalToPay.set(feeAndSecDeposit.add(amount.get()));
else else
totalToPayAsCoin.set(feeAndSecDeposit); totalToPay.set(feeAndSecDeposit);
updateAvailableBalance(); updateAvailableBalance();
log.debug("totalToPayAsCoin {}", totalToPayAsCoin.get().toFriendlyString()); log.debug("totalToPay {}", totalToPay.get());
} }
} }
@ -433,7 +429,7 @@ class TakeOfferDataModel extends OfferDataModel {
} }
@Nullable @Nullable
Coin getTakerFee() { BigInteger getTakerFee() {
return HavenoUtils.getTakerFee(this.amount.get()); return HavenoUtils.getTakerFee(this.amount.get());
} }
@ -450,33 +446,22 @@ class TakeOfferDataModel extends OfferDataModel {
boolean isMinAmountLessOrEqualAmount() { boolean isMinAmountLessOrEqualAmount() {
//noinspection SimplifiableIfStatement //noinspection SimplifiableIfStatement
if (offer != null && amount.get() != null) if (offer != null && amount.get() != null)
return !offer.getMinAmount().isGreaterThan(amount.get()); return offer.getMinAmount().compareTo(amount.get()) <= 0;
return true; return true;
} }
boolean isAmountLargerThanOfferAmount() { boolean isAmountLargerThanOfferAmount() {
//noinspection SimplifiableIfStatement //noinspection SimplifiableIfStatement
if (amount.get() != null && offer != null) if (amount.get() != null && offer != null)
return amount.get().isGreaterThan(offer.getAmount()); return amount.get().compareTo(offer.getAmount()) > 0;
return true; return true;
} }
boolean wouldCreateDustForMaker() { boolean wouldCreateDustForMaker() {
//noinspection SimplifiableIfStatement return false; // TODO: update for XMR?
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;
} }
ReadOnlyObjectProperty<Coin> getAmount() { ReadOnlyObjectProperty<BigInteger> getAmount() {
return amount; return amount;
} }
@ -493,7 +478,7 @@ class TakeOfferDataModel extends OfferDataModel {
} }
@NotNull @NotNull
private Coin getFundsNeededForTrade() { private BigInteger getFundsNeededForTrade() {
return getSecurityDeposit(); return getSecurityDeposit();
} }
@ -501,15 +486,15 @@ class TakeOfferDataModel extends OfferDataModel {
return addressEntry; return addressEntry;
} }
public Coin getSecurityDeposit() { public BigInteger getSecurityDeposit() {
return securityDeposit; return securityDeposit;
} }
public Coin getBuyerSecurityDeposit() { public BigInteger getBuyerSecurityDeposit() {
return offer.getBuyerSecurityDeposit(); return offer.getBuyerSecurityDeposit();
} }
public Coin getSellerSecurityDeposit() { public BigInteger getSellerSecurityDeposit() {
return offer.getSellerSecurityDeposit(); return offer.getSellerSecurityDeposit();
} }

View File

@ -54,6 +54,7 @@ import bisq.core.offer.Offer;
import bisq.core.payment.FasterPaymentsAccount; import bisq.core.payment.FasterPaymentsAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.HavenoUtils;
import bisq.core.user.DontShowAgainLookup; import bisq.core.user.DontShowAgainLookup;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
@ -65,8 +66,6 @@ import bisq.common.util.Tuple3;
import bisq.common.util.Tuple4; import bisq.common.util.Tuple4;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
import net.glxn.qrgen.QRCode; import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType; import net.glxn.qrgen.image.ImageType;
@ -108,6 +107,7 @@ import javafx.beans.value.ChangeListener;
import java.net.URI; import java.net.URI;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -208,7 +208,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
if (newValue) { if (newValue) {
Notification walletFundedNotification = new Notification() Notification walletFundedNotification = new Notification()
.headLine(Res.get("notification.walletUpdate.headline")) .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(); .autoClose();
walletFundedNotification.show(); walletFundedNotification.show();
@ -262,7 +262,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
model.onPaymentAccountSelected(lastPaymentAccount); model.onPaymentAccountSelected(lastPaymentAccount);
} }
balanceTextField.setTargetAmount(model.dataModel.getTotalToPayAsCoin().get()); balanceTextField.setTargetAmount(model.dataModel.getTotalToPay().get());
maybeShowTakeOfferFromUnsignedAccountWarning(model.dataModel.getOffer()); maybeShowTakeOfferFromUnsignedAccountWarning(model.dataModel.getOffer());
maybeShowClearXchangeWarning(lastPaymentAccount); 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 // Called from parent as the view does not get notified when the tab is closed
public void onClose() { public void onClose() {
Coin availableBalance = model.dataModel.getAvailableBalance().get(); BigInteger availableBalance = model.dataModel.getAvailableBalance().get();
if (availableBalance != null && availableBalance.isPositive() && !model.takeOfferCompleted.get() && !DevEnv.isDevMode()) { if (availableBalance != null && availableBalance.compareTo(BigInteger.valueOf(0)) > 0 && !model.takeOfferCompleted.get() && !DevEnv.isDevMode()) {
model.dataModel.swapTradeToSavings(); model.dataModel.swapTradeToSavings();
} }
} }
@ -445,7 +445,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
updateOfferElementsStyle(); updateOfferElementsStyle();
balanceTextField.setTargetAmount(model.dataModel.getTotalToPayAsCoin().get()); balanceTextField.setTargetAmount(model.dataModel.getTotalToPay().get());
if (!DevEnv.isDevMode()) { if (!DevEnv.isDevMode()) {
String tradeAmountText = model.isSeller() ? Res.get("takeOffer.takeOfferFundWalletInfo.tradeAmount", model.getTradeAmount()) : ""; 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) { if (walletFundedNotification == null) {
walletFundedNotification = new Notification() walletFundedNotification = new Notification()
.headLine(Res.get("notification.walletUpdate.headline")) .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(); .autoClose();
walletFundedNotification.show(); walletFundedNotification.show();
} }
@ -542,7 +542,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
amountTextField.textProperty().bindBidirectional(model.amount); amountTextField.textProperty().bindBidirectional(model.amount);
volumeTextField.textProperty().bindBidirectional(model.volume); volumeTextField.textProperty().bindBidirectional(model.volume);
totalToPayTextField.textProperty().bind(model.totalToPay); totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.dataModel.getMissingCoin()); addressTextField.amountAsProperty().bind(model.dataModel.getMissingCoin());
amountTextField.validationResultProperty().bind(model.amountValidationResult); amountTextField.validationResultProperty().bind(model.amountValidationResult);
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> CurrencyUtil.getCounterCurrency(model.dataModel.getCurrencyCode()))); priceCurrencyLabel.textProperty().bind(createStringBinding(() -> CurrencyUtil.getCounterCurrency(model.dataModel.getCurrencyCode())));
priceAsPercentageLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty()); priceAsPercentageLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty());
@ -566,7 +566,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
amountTextField.textProperty().unbindBidirectional(model.amount); amountTextField.textProperty().unbindBidirectional(model.amount);
volumeTextField.textProperty().unbindBidirectional(model.volume); volumeTextField.textProperty().unbindBidirectional(model.volume);
totalToPayTextField.textProperty().unbind(); totalToPayTextField.textProperty().unbind();
addressTextField.amountAsCoinProperty().unbind(); addressTextField.amountAsProperty().unbind();
amountTextField.validationResultProperty().unbind(); amountTextField.validationResultProperty().unbind();
priceCurrencyLabel.textProperty().unbind(); priceCurrencyLabel.textProperty().unbind();
priceAsPercentageLabel.prefWidthProperty().unbind(); priceAsPercentageLabel.prefWidthProperty().unbind();

View File

@ -37,7 +37,7 @@ import bisq.core.offer.OfferRestrictions;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; 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.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
@ -52,8 +52,6 @@ import bisq.network.p2p.network.Connection;
import bisq.network.p2p.network.ConnectionListener; import bisq.network.p2p.network.ConnectionListener;
import bisq.common.UserThread; import bisq.common.UserThread;
import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -78,10 +76,12 @@ import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static javafx.beans.binding.Bindings.createStringBinding; import static javafx.beans.binding.Bindings.createStringBinding;
import java.math.BigInteger;
class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> implements ViewModel { class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> implements ViewModel {
final TakeOfferDataModel dataModel; final TakeOfferDataModel dataModel;
private final OfferUtil offerUtil; private final OfferUtil offerUtil;
private final BtcValidator btcValidator; private final XmrValidator btcValidator;
private final P2PService p2PService; private final P2PService p2PService;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final Navigation navigation; private final Navigation navigation;
@ -118,8 +118,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>(); final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>();
private ChangeListener<String> amountListener; private ChangeListener<String> amountStrListener;
private ChangeListener<Coin> amountAsCoinListener; private ChangeListener<BigInteger> amountListener;
private ChangeListener<Boolean> isWalletFundedListener; private ChangeListener<Boolean> isWalletFundedListener;
private ChangeListener<Trade.State> tradeStateListener; private ChangeListener<Trade.State> tradeStateListener;
private ChangeListener<Offer.State> offerStateListener; private ChangeListener<Offer.State> offerStateListener;
@ -136,7 +136,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
@Inject @Inject
public TakeOfferViewModel(TakeOfferDataModel dataModel, public TakeOfferViewModel(TakeOfferDataModel dataModel,
OfferUtil offerUtil, OfferUtil offerUtil,
BtcValidator btcValidator, XmrValidator btcValidator,
P2PService p2PService, P2PService p2PService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
Navigation navigation, Navigation navigation,
@ -168,7 +168,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
volumeDescriptionLabel.set(Res.get(sellVolumeDescriptionKey, dataModel.getCurrencyCode())); volumeDescriptionLabel.set(Res.get(sellVolumeDescriptionKey, dataModel.getCurrencyCode()));
} }
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get())); amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
showTransactionPublishedScreen.set(false); showTransactionPublishedScreen.set(false);
// when getting back to an open screen we want to re-check again // 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(buyAmountDescriptionKey)
: Res.get(sellAmountDescriptionKey); : 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); price = FormattingUtils.formatPrice(dataModel.tradePrice);
marketPriceMargin = FormattingUtils.formatToPercent(offer.getMarketPriceMarginPct()); marketPriceMargin = FormattingUtils.formatToPercent(offer.getMarketPriceMarginPct());
paymentLabel = Res.get("takeOffer.fundsBox.paymentLabel", offer.getShortId()); paymentLabel = Res.get("takeOffer.fundsBox.paymentLabel", offer.getShortId());
@ -219,7 +219,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
errorMessage.set(offer.getErrorMessage()); errorMessage.set(offer.getErrorMessage());
btcValidator.setMaxValue(offer.getAmount()); 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()); btcValidator.setMinValue(offer.getMinAmount());
} }
@ -248,7 +248,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
public void onPaymentAccountSelected(PaymentAccount paymentAccount) { public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
dataModel.onPaymentAccountSelected(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(); updateButtonDisableState();
} }
@ -265,8 +265,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
return true; return true;
} else { } else {
new Popup().warning(Res.get("shared.notEnoughFunds", new Popup().warning(Res.get("shared.notEnoughFunds",
xmrFormatter.formatCoinWithCode(dataModel.getTotalToPayAsCoin().get()), HavenoUtils.formatToXmrWithCode(dataModel.getTotalToPay().get()),
xmrFormatter.formatCoinWithCode(dataModel.getTotalAvailableBalance()))) HavenoUtils.formatToXmrWithCode(dataModel.getTotalAvailableBalance())))
.actionButtonTextWithGoTo("navigation.funds.depositFunds") .actionButtonTextWithGoTo("navigation.funds.depositFunds")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class)) .onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
.show(); .show();
@ -276,13 +276,13 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private void applyTakerFee() { private void applyTakerFee() {
tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly")); tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly"));
Coin takerFeeAsCoin = dataModel.getTakerFee(); BigInteger takerFee = dataModel.getTakerFee();
if (takerFeeAsCoin == null) { if (takerFee == null) {
return; return;
} }
isTradeFeeVisible.setValue(true); isTradeFeeVisible.setValue(true);
tradeFee.set(getFormatterForTakerFee().formatCoin(takerFeeAsCoin)); tradeFee.set(HavenoUtils.formatToXmr(takerFee));
tradeFeeInXmrWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, tradeFeeInXmrWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
dataModel.getTakerFee(), dataModel.getTakerFee(),
xmrFormatter)); xmrFormatter));
@ -303,27 +303,27 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
// only allow max 4 decimal places for btc values // only allow max 4 decimal places for btc values
setAmountToModel(); setAmountToModel();
// reformat input // reformat input
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get())); amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
calculateVolume(); calculateVolume();
Price tradePrice = dataModel.tradePrice; Price tradePrice = dataModel.tradePrice;
long maxTradeLimit = dataModel.getMaxTradeLimit(); long maxTradeLimit = dataModel.getMaxTradeLimit();
if (dataModel.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) { if (dataModel.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) {
Coin adjustedAmountForHalCash = CoinUtil.getAdjustedAmountForHalCash(dataModel.getAmount().get(), BigInteger adjustedAmountForHalCash = CoinUtil.getAdjustedAmountForHalCash(dataModel.getAmount().get(),
tradePrice, tradePrice,
maxTradeLimit); maxTradeLimit);
dataModel.applyAmount(adjustedAmountForHalCash); dataModel.applyAmount(adjustedAmountForHalCash);
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get())); amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
} else if (dataModel.getOffer().isFiatOffer()) { } else if (dataModel.getOffer().isFiatOffer()) {
if (!isAmountEqualMinAmount(dataModel.getAmount().get()) && (!isAmountEqualMaxAmount(dataModel.getAmount().get()))) { if (!isAmountEqualMinAmount(dataModel.getAmount().get()) && (!isAmountEqualMaxAmount(dataModel.getAmount().get()))) {
// We only apply the rounding if the amount is variable (minAmount is lower as amount). // We only apply the rounding if the amount is variable (minAmount is lower as amount).
// Otherwise we could get an amount lower then the minAmount set by rounding // 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); maxTradeLimit);
dataModel.applyAmount(roundedAmount); dataModel.applyAmount(roundedAmount);
} }
amount.set(xmrFormatter.formatCoin(dataModel.getAmount().get())); amount.set(HavenoUtils.formatToXmr(dataModel.getAmount().get()));
} }
if (!dataModel.isMinAmountLessOrEqualAmount()) if (!dataModel.isMinAmountLessOrEqualAmount())
@ -337,16 +337,16 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
if (dataModel.wouldCreateDustForMaker()) if (dataModel.wouldCreateDustForMaker())
amountValidationResult.set(new InputValidator.ValidationResult(false, amountValidationResult.set(new InputValidator.ValidationResult(false,
Res.get("takeOffer.validation.amountLargerThanOfferAmountMinusFee"))); 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) { if (dataModel.getDirection() == OfferDirection.BUY) {
new Popup().information(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.seller", 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"))) Res.get("offerbook.warning.newVersionAnnouncement")))
.width(900) .width(900)
.show(); .show();
} else { } else {
new Popup().information(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.buyer", 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"))) Res.get("offerbook.warning.newVersionAnnouncement")))
.width(900) .width(900)
.show(); .show();
@ -468,7 +468,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private void addBindings() { private void addBindings() {
volume.bind(createStringBinding(() -> VolumeUtil.formatVolume(dataModel.volume.get()), dataModel.volume)); 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() { private void createListeners() {
amountListener = (ov, oldValue, newValue) -> { amountStrListener = (ov, oldValue, newValue) -> {
if (isBtcInputValid(newValue).isValid) { if (isBtcInputValid(newValue).isValid) {
setAmountToModel(); setAmountToModel();
calculateVolume(); calculateVolume();
@ -488,8 +488,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
} }
updateButtonDisableState(); updateButtonDisableState();
}; };
amountAsCoinListener = (ov, oldValue, newValue) -> { amountListener = (ov, oldValue, newValue) -> {
amount.set(xmrFormatter.formatCoin(newValue)); amount.set(HavenoUtils.formatToXmr(newValue));
applyTakerFee(); applyTakerFee();
}; };
isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState(); isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState();
@ -548,10 +548,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private void addListeners() { private void addListeners() {
// Bidirectional bindings are used for all input fields: amount, price, volume and minAmount // 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 // 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 // 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.getIsXmrWalletFunded().addListener(isWalletFundedListener);
dataModel.getMempoolStatus().addListener(getMempoolStatusListener); dataModel.getMempoolStatus().addListener(getMempoolStatusListener);
@ -563,10 +563,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
} }
private void removeListeners() { private void removeListeners() {
amount.removeListener(amountListener); amount.removeListener(amountStrListener);
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding // 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.getMempoolStatus().removeListener(getMempoolStatusListener);
dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener); dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener);
@ -592,7 +592,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private void setAmountToModel() { private void setAmountToModel() {
if (amount.get() != null && !amount.get().isEmpty()) { if (amount.get() != null && !amount.get().isEmpty()) {
Coin amount = DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter); BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter));
long maxTradeLimit = dataModel.getMaxTradeLimit(); long maxTradeLimit = dataModel.getMaxTradeLimit();
Price price = dataModel.tradePrice; Price price = dataModel.tradePrice;
if (price != null) { if (price != null) {
@ -609,12 +609,12 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
} }
} }
private boolean isAmountEqualMinAmount(Coin amount) { private boolean isAmountEqualMinAmount(BigInteger amount) {
return amount.value == offer.getMinAmount().value; return offer.getMinAmount().equals(amount);
} }
private boolean isAmountEqualMaxAmount(Coin amount) { private boolean isAmountEqualMaxAmount(BigInteger amount) {
return amount.value == offer.getAmount().value; return offer.getAmount().equals(amount);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -679,12 +679,12 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
dataModel.getSecurityDeposit(), dataModel.getSecurityDeposit(),
dataModel.getAmount().get(), dataModel.getAmount().get(),
xmrFormatter, xmrFormatter,
Restrictions.getMinBuyerSecurityDepositAsCoin() Restrictions.getMinBuyerSecurityDeposit()
); );
} }
public String getSecurityDepositWithCode() { public String getSecurityDepositWithCode() {
return xmrFormatter.formatCoinWithCode(dataModel.getSecurityDeposit()); return HavenoUtils.formatToXmrWithCode(dataModel.getSecurityDeposit());
} }
public String getTradeFee() { public String getTradeFee() {
@ -696,8 +696,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
} }
public String getTakerFeePercentage() { public String getTakerFeePercentage() {
final Coin takerFeeAsCoin = dataModel.getTakerFee(); final BigInteger takerFee = dataModel.getTakerFee();
return takerFeeAsCoin != null ? GUIUtil.getPercentage(takerFeeAsCoin, dataModel.getAmount().get()) : Res.get("shared.na"); return takerFee != null ? GUIUtil.getPercentage(takerFee, dataModel.getAmount().get()) : Res.get("shared.na");
} }
public String getTotalToPayInfo() { public String getTotalToPayInfo() {

View File

@ -25,10 +25,8 @@ import bisq.desktop.util.Layout;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CountryUtil; import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.support.dispute.Dispute; import bisq.core.support.dispute.Dispute;
import bisq.core.support.dispute.DisputeList; 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.mediation.MediationManager;
import bisq.core.support.dispute.refund.RefundManager; import bisq.core.support.dispute.refund.RefundManager;
import bisq.core.trade.Contract; import bisq.core.trade.Contract;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.VolumeUtil; import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinFormatter;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.common.crypto.PubKeyRing;
import org.bitcoinj.core.Utils; import org.bitcoinj.core.Utils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
@ -80,7 +76,6 @@ public class ContractWindow extends Overlay<ContractWindow> {
private final MediationManager mediationManager; private final MediationManager mediationManager;
private final RefundManager refundManager; private final RefundManager refundManager;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final CoinFormatter formatter;
private Dispute dispute; private Dispute dispute;
@ -92,13 +87,11 @@ public class ContractWindow extends Overlay<ContractWindow> {
public ContractWindow(ArbitrationManager arbitrationManager, public ContractWindow(ArbitrationManager arbitrationManager,
MediationManager mediationManager, MediationManager mediationManager,
RefundManager refundManager, RefundManager refundManager,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService) {
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
this.arbitrationManager = arbitrationManager; this.arbitrationManager = arbitrationManager;
this.mediationManager = mediationManager; this.mediationManager = mediationManager;
this.refundManager = refundManager; this.refundManager = refundManager;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.formatter = formatter;
type = Type.Confirmation; type = Type.Confirmation;
} }
@ -160,18 +153,18 @@ public class ContractWindow extends Overlay<ContractWindow> {
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradePrice"), addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
FormattingUtils.formatPrice(contract.getPrice())); FormattingUtils.formatPrice(contract.getPrice()));
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradeAmount"), addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradeAmount"),
formatter.formatCoinWithCode(contract.getTradeAmount())); HavenoUtils.formatToXmrWithCode(contract.getTradeAmount()));
addConfirmationLabelTextField(gridPane, addConfirmationLabelTextField(gridPane,
++rowIndex, ++rowIndex,
VolumeUtil.formatVolumeLabel(currencyCode, ":"), VolumeUtil.formatVolumeLabel(currencyCode, ":"),
VolumeUtil.formatVolumeWithCode(contract.getTradeVolume())); VolumeUtil.formatVolumeWithCode(contract.getTradeVolume()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") + String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " + " " +
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) + HavenoUtils.formatToXmrWithCode(offer.getBuyerSecurityDeposit()) +
" / " + " / " +
Res.getWithColAndCap("shared.seller") + Res.getWithColAndCap("shared.seller") +
" " + " " +
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit()); HavenoUtils.formatToXmrWithCode(offer.getSellerSecurityDeposit());
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
addConfirmationLabelTextField(gridPane, addConfirmationLabelTextField(gridPane,
++rowIndex, ++rowIndex,

View File

@ -43,7 +43,6 @@ import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.ParsingUtils;
import bisq.core.util.VolumeUtil; import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
@ -76,6 +75,7 @@ import javafx.geometry.Insets;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
import java.util.Optional; 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("disputeSummaryWindow.role"), role);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeAmount"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeAmount"),
formatter.formatCoinWithCode(contract.getTradeAmount())); HavenoUtils.formatToXmrWithCode(contract.getTradeAmount()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
FormattingUtils.formatPrice(contract.getPrice())); FormattingUtils.formatPrice(contract.getPrice()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeVolume"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeVolume"),
VolumeUtil.formatVolumeWithCode(contract.getTradeVolume())); VolumeUtil.formatVolumeWithCode(contract.getTradeVolume()));
String tradeFee = Res.getWithColAndCap("shared.buyer") + 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") + 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); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeFee"), tradeFee);
String securityDeposit = Res.getWithColAndCap("shared.buyer") + String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " + " " +
formatter.formatCoinWithCode(trade.getBuyerSecurityDeposit()) + HavenoUtils.formatToXmrWithCode(trade.getBuyerSecurityDeposit()) +
" / " + " / " +
Res.getWithColAndCap("shared.seller") + Res.getWithColAndCap("shared.seller") +
" " + " " +
formatter.formatCoinWithCode(trade.getSellerSecurityDeposit()); HavenoUtils.formatToXmrWithCode(trade.getSellerSecurityDeposit());
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
} }
@ -356,14 +356,14 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
} }
private boolean isPayoutAmountValid() { private boolean isPayoutAmountValid() {
Coin buyerAmount = ParsingUtils.parseToCoin(buyerPayoutAmountInputTextField.getText(), formatter); BigInteger buyerAmount = HavenoUtils.parseXmr(buyerPayoutAmountInputTextField.getText());
Coin sellerAmount = ParsingUtils.parseToCoin(sellerPayoutAmountInputTextField.getText(), formatter); BigInteger sellerAmount = HavenoUtils.parseXmr(sellerPayoutAmountInputTextField.getText());
Contract contract = dispute.getContract(); Contract contract = dispute.getContract();
Coin tradeAmount = contract.getTradeAmount(); BigInteger tradeAmount = contract.getTradeAmount();
Coin available = tradeAmount BigInteger available = tradeAmount
.add(trade.getBuyerSecurityDeposit()) .add(trade.getBuyerSecurityDeposit())
.add(trade.getSellerSecurityDeposit()); .add(trade.getSellerSecurityDeposit());
Coin totalAmount = buyerAmount.add(sellerAmount); BigInteger totalAmount = buyerAmount.add(sellerAmount);
boolean isRefundAgent = getDisputeManager(dispute) instanceof RefundManager; boolean isRefundAgent = getDisputeManager(dispute) instanceof RefundManager;
if (isRefundAgent) { if (isRefundAgent) {
@ -371,7 +371,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
// be made // be made
return totalAmount.compareTo(available) <= 0; return totalAmount.compareTo(available) <= 0;
} else { } else {
if (!totalAmount.isPositive()) { if (totalAmount.compareTo(BigInteger.valueOf(0)) <= 0) {
return false; return false;
} }
return totalAmount.compareTo(available) == 0; return totalAmount.compareTo(available) == 0;
@ -386,26 +386,26 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
} }
Contract contract = dispute.getContract(); Contract contract = dispute.getContract();
Coin available = contract.getTradeAmount() BigInteger available = contract.getTradeAmount()
.add(trade.getBuyerSecurityDeposit()) .add(trade.getBuyerSecurityDeposit())
.add(trade.getSellerSecurityDeposit()); .add(trade.getSellerSecurityDeposit());
Coin enteredAmount = ParsingUtils.parseToCoin(inputTextField.getText(), formatter); BigInteger enteredAmount = HavenoUtils.parseXmr(inputTextField.getText());
if (enteredAmount.compareTo(available) > 0) { if (enteredAmount.compareTo(available) > 0) {
enteredAmount = available; enteredAmount = available;
Coin finalEnteredAmount = enteredAmount; BigInteger finalEnteredAmount = enteredAmount;
inputTextField.setText(formatter.formatCoin(finalEnteredAmount)); inputTextField.setText(HavenoUtils.formatToXmr(finalEnteredAmount));
} }
Coin counterPartAsCoin = available.subtract(enteredAmount); BigInteger counterPart = available.subtract(enteredAmount);
String formattedCounterPartAmount = formatter.formatCoin(counterPartAsCoin); String formattedCounterPartAmount = HavenoUtils.formatToXmr(counterPart);
Coin buyerAmount; BigInteger buyerAmount;
Coin sellerAmount; BigInteger sellerAmount;
if (inputTextField == buyerPayoutAmountInputTextField) { if (inputTextField == buyerPayoutAmountInputTextField) {
buyerAmount = enteredAmount; buyerAmount = enteredAmount;
sellerAmount = counterPartAsCoin; sellerAmount = counterPart;
sellerPayoutAmountInputTextField.setText(formattedCounterPartAmount); sellerPayoutAmountInputTextField.setText(formattedCounterPartAmount);
} else { } else {
sellerAmount = enteredAmount; sellerAmount = enteredAmount;
buyerAmount = counterPartAsCoin; buyerAmount = counterPart;
buyerPayoutAmountInputTextField.setText(formattedCounterPartAmount); buyerPayoutAmountInputTextField.setText(formattedCounterPartAmount);
} }
@ -619,28 +619,28 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
} }
private void showPayoutTxConfirmation(Contract contract, DisputeResult disputeResult, MoneroTxWallet payoutTx, ResultHandler resultHandler) { private void showPayoutTxConfirmation(Contract contract, DisputeResult disputeResult, MoneroTxWallet payoutTx, ResultHandler resultHandler) {
Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount(); BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
String buyerPayoutAddressString = contract.getBuyerPayoutAddressString(); String buyerPayoutAddressString = contract.getBuyerPayoutAddressString();
Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount(); BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
String sellerPayoutAddressString = contract.getSellerPayoutAddressString(); String sellerPayoutAddressString = contract.getSellerPayoutAddressString();
Coin outputAmount = buyerPayoutAmount.add(sellerPayoutAmount); BigInteger outputAmount = buyerPayoutAmount.add(sellerPayoutAmount);
String buyerDetails = ""; String buyerDetails = "";
if (buyerPayoutAmount.isPositive()) { if (buyerPayoutAmount.compareTo(BigInteger.valueOf(0)) > 0) {
buyerDetails = Res.get("disputeSummaryWindow.close.txDetails.buyer", buyerDetails = Res.get("disputeSummaryWindow.close.txDetails.buyer",
formatter.formatCoinWithCode(buyerPayoutAmount), HavenoUtils.formatToXmrWithCode(buyerPayoutAmount),
buyerPayoutAddressString); buyerPayoutAddressString);
} }
String sellerDetails = ""; String sellerDetails = "";
if (sellerPayoutAmount.isPositive()) { if (sellerPayoutAmount.compareTo(BigInteger.valueOf(0)) > 0) {
sellerDetails = Res.get("disputeSummaryWindow.close.txDetails.seller", sellerDetails = Res.get("disputeSummaryWindow.close.txDetails.seller",
formatter.formatCoinWithCode(sellerPayoutAmount), HavenoUtils.formatToXmrWithCode(sellerPayoutAmount),
sellerPayoutAddressString); sellerPayoutAddressString);
} }
if (outputAmount.isPositive()) { if (outputAmount.compareTo(BigInteger.valueOf(0)) > 0) {
new Popup().width(900) new Popup().width(900)
.headLine(Res.get("disputeSummaryWindow.close.txDetails.headline")) .headLine(Res.get("disputeSummaryWindow.close.txDetails.headline"))
.confirmation(Res.get("disputeSummaryWindow.close.txDetails", .confirmation(Res.get("disputeSummaryWindow.close.txDetails",
formatter.formatCoinWithCode(outputAmount), HavenoUtils.formatToXmrWithCode(outputAmount),
buyerDetails, buyerDetails,
sellerDetails, sellerDetails,
formatter.formatCoinWithCode(HavenoUtils.atomicUnitsToCoin(payoutTx.getFee())))) formatter.formatCoinWithCode(HavenoUtils.atomicUnitsToCoin(payoutTx.getFee()))))
@ -716,21 +716,21 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
throw new IllegalStateException("Unknown radio button"); throw new IllegalStateException("Unknown radio button");
} }
disputesService.applyPayoutAmountsToDisputeResult(payout, dispute, disputeResult, -1); disputesService.applyPayoutAmountsToDisputeResult(payout, dispute, disputeResult, -1);
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(disputeResult.getBuyerPayoutAmount())); buyerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(disputeResult.getBuyerPayoutAmount()));
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(disputeResult.getSellerPayoutAmount())); sellerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(disputeResult.getSellerPayoutAmount()));
} }
private void applyTradeAmountRadioButtonStates() { private void applyTradeAmountRadioButtonStates() {
Contract contract = dispute.getContract(); Contract contract = dispute.getContract();
Coin buyerSecurityDeposit = trade.getBuyerSecurityDeposit(); BigInteger buyerSecurityDeposit = trade.getBuyerSecurityDeposit();
Coin sellerSecurityDeposit = trade.getSellerSecurityDeposit(); BigInteger sellerSecurityDeposit = trade.getSellerSecurityDeposit();
Coin tradeAmount = contract.getTradeAmount(); BigInteger tradeAmount = contract.getTradeAmount();
Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount(); BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount(); BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(buyerPayoutAmount)); buyerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(buyerPayoutAmount));
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(sellerPayoutAmount)); sellerPayoutAmountInputTextField.setText(HavenoUtils.formatToXmr(sellerPayoutAmount));
if (buyerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit)) && if (buyerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit)) &&
sellerPayoutAmount.equals(sellerSecurityDeposit)) { sellerPayoutAmount.equals(sellerSecurityDeposit)) {

View File

@ -32,6 +32,7 @@ import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection; import bisq.core.offer.OfferDirection;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.trade.Trade.State; import bisq.core.trade.Trade.State;
@ -44,7 +45,6 @@ import bisq.common.crypto.KeyRing;
import bisq.common.util.Tuple2; import bisq.common.util.Tuple2;
import bisq.common.util.Tuple4; import bisq.common.util.Tuple4;
import org.bitcoinj.core.Coin;
import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.Subscription;
@ -64,6 +64,7 @@ import javafx.scene.layout.HBox;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import java.math.BigInteger;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -80,7 +81,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
private final KeyRing keyRing; private final KeyRing keyRing;
private final Navigation navigation; private final Navigation navigation;
private Offer offer; private Offer offer;
private Coin tradeAmount; private BigInteger tradeAmount;
private Price tradePrice; private Price tradePrice;
private Optional<Runnable> placeOfferHandlerOptional = Optional.empty(); private Optional<Runnable> placeOfferHandlerOptional = Optional.empty();
private Optional<Runnable> takeOfferHandlerOptional = Optional.empty(); private Optional<Runnable> takeOfferHandlerOptional = Optional.empty();
@ -106,7 +107,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
type = Type.Confirmation; 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.offer = offer;
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
this.tradePrice = tradePrice; this.tradePrice = tradePrice;
@ -208,14 +209,14 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
String btcAmount = Res.get("shared.btcAmount"); String btcAmount = Res.get("shared.btcAmount");
if (takeOfferHandlerOptional.isPresent()) { if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo,
formatter.formatCoinWithCode(tradeAmount)); HavenoUtils.formatToXmrWithCode(tradeAmount));
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + fiatDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + fiatDirectionInfo,
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount))); VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
} else { } else {
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo,
formatter.formatCoinWithCode(offer.getAmount())); HavenoUtils.formatToXmrWithCode(offer.getAmount()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minBtcAmount"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minBtcAmount"),
formatter.formatCoinWithCode(offer.getMinAmount())); HavenoUtils.formatToXmrWithCode(offer.getMinAmount()));
String volume = VolumeUtil.formatVolumeWithCode(offer.getVolume()); String volume = VolumeUtil.formatVolumeWithCode(offer.getVolume());
String minVolume = ""; String minVolume = "";
if (offer.getVolume() != null && offer.getMinVolume() != null && if (offer.getVolume() != null && offer.getMinVolume() != null &&
@ -324,11 +325,11 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
DisplayUtils.formatDateTime(offer.getDate())); DisplayUtils.formatDateTime(offer.getDate()));
String value = Res.getWithColAndCap("shared.buyer") + String value = Res.getWithColAndCap("shared.buyer") +
" " + " " +
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) + HavenoUtils.formatToXmrWithCode(offer.getBuyerSecurityDeposit()) +
" / " + " / " +
Res.getWithColAndCap("shared.seller") + Res.getWithColAndCap("shared.seller") +
" " + " " +
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit()); HavenoUtils.formatToXmrWithCode(offer.getSellerSecurityDeposit());
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
if (countryCode != null && !isF2F) if (countryCode != null && !isF2F)

View File

@ -31,6 +31,7 @@ import bisq.core.offer.Offer;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.support.dispute.arbitration.ArbitrationManager; import bisq.core.support.dispute.arbitration.ArbitrationManager;
import bisq.core.trade.Contract; import bisq.core.trade.Contract;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.trade.txproof.AssetTxProofResult; import bisq.core.trade.txproof.AssetTxProofResult;
@ -162,7 +163,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
} }
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.btcAmount") + btcDirectionInfo, addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.btcAmount") + btcDirectionInfo,
formatter.formatCoinWithCode(trade.getAmount())); HavenoUtils.formatToXmrWithCode(trade.getAmount()));
addConfirmationLabelTextField(gridPane, ++rowIndex, addConfirmationLabelTextField(gridPane, ++rowIndex,
VolumeUtil.formatVolumeLabel(offer.getCurrencyCode()) + fiatDirectionInfo, VolumeUtil.formatVolumeLabel(offer.getCurrencyCode()) + fiatDirectionInfo,
VolumeUtil.formatVolumeWithCode(trade.getVolume())); VolumeUtil.formatVolumeWithCode(trade.getVolume()));
@ -215,11 +216,11 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
DisplayUtils.formatDateTime(trade.getDate())); DisplayUtils.formatDateTime(trade.getDate()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") + String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " + " " +
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) + HavenoUtils.formatToXmrWithCode(offer.getBuyerSecurityDeposit()) +
" / " + " / " +
Res.getWithColAndCap("shared.seller") + Res.getWithColAndCap("shared.seller") +
" " + " " +
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit()); HavenoUtils.formatToXmrWithCode(offer.getSellerSecurityDeposit());
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
NodeAddress arbitratorNodeAddress = trade.getArbitratorNodeAddress(); NodeAddress arbitratorNodeAddress = trade.getArbitratorNodeAddress();

View File

@ -29,10 +29,10 @@ import bisq.core.trade.ClosedTradableFormatter;
import bisq.core.trade.ClosedTradableManager; import bisq.core.trade.ClosedTradableManager;
import bisq.core.trade.Tradable; import bisq.core.trade.Tradable;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import org.bitcoinj.core.Coin;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.math.BigInteger;
import java.util.Date; import java.util.Date;
import lombok.Getter; import lombok.Getter;
@ -57,7 +57,7 @@ public class ClosedTradesListItem implements FilterableListItem {
return tradable.getShortId(); return tradable.getShortId();
} }
public Coin getAmount() { public BigInteger getAmount() {
return tradable.getOptionalAmount().orElse(null); return tradable.getOptionalAmount().orElse(null);
} }

View File

@ -41,12 +41,11 @@ import bisq.core.util.coin.CoinUtil;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import org.bitcoinj.core.Coin;
import com.google.inject.Inject; import com.google.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import java.math.BigInteger;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -100,7 +99,7 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
} }
private double getBuyerSecurityAsPercent(Offer offer) { private double getBuyerSecurityAsPercent(Offer offer) {
Coin offerBuyerSecurityDeposit = getBoundedBuyerSecurityDepositAsCoin(offer.getBuyerSecurityDeposit()); BigInteger offerBuyerSecurityDeposit = getBoundedBuyerSecurityDeposit(offer.getBuyerSecurityDeposit());
double offerBuyerSecurityDepositAsPercent = CoinUtil.getAsPercentPerBtc(offerBuyerSecurityDeposit, double offerBuyerSecurityDepositAsPercent = CoinUtil.getAsPercentPerBtc(offerBuyerSecurityDeposit,
offer.getAmount()); offer.getAmount());
return Math.min(offerBuyerSecurityDepositAsPercent, return Math.min(offerBuyerSecurityDepositAsPercent,

View File

@ -23,7 +23,7 @@ import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload; import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil; 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.FiatVolumeValidator;
import bisq.core.payment.validation.SecurityDepositValidator; import bisq.core.payment.validation.SecurityDepositValidator;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
@ -46,7 +46,7 @@ class DuplicateOfferViewModel extends MutableOfferViewModel<DuplicateOfferDataMo
FiatVolumeValidator fiatVolumeValidator, FiatVolumeValidator fiatVolumeValidator,
FiatPriceValidator fiatPriceValidator, FiatPriceValidator fiatPriceValidator,
AltcoinValidator altcoinValidator, AltcoinValidator altcoinValidator,
BtcValidator btcValidator, XmrValidator btcValidator,
SecurityDepositValidator securityDepositValidator, SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,

Some files were not shown because too many files have changed in this diff Show More