From 4edf83b5c99588e7f5a0eb4054bf0f61a2800ca9 Mon Sep 17 00:00:00 2001 From: woodser Date: Wed, 16 Oct 2024 15:19:34 -0400 Subject: [PATCH] validate pending offer --- .../main/java/haveno/core/offer/Offer.java | 2 +- .../haveno/core/offer/OpenOfferManager.java | 9 ++ .../offer/placeoffer/tasks/ValidateOffer.java | 119 +++++++++--------- 3 files changed, 73 insertions(+), 57 deletions(-) diff --git a/core/src/main/java/haveno/core/offer/Offer.java b/core/src/main/java/haveno/core/offer/Offer.java index 675fbeb550c..b3c81c5bcff 100644 --- a/core/src/main/java/haveno/core/offer/Offer.java +++ b/core/src/main/java/haveno/core/offer/Offer.java @@ -200,7 +200,7 @@ public Price getPrice() { return null; } } else { - log.trace("We don't have a market price. " + + log.warn("We don't have a market price. " + "That case could only happen if you don't have a price feed."); return null; } diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index ffed498bc9c..bdee3e23c72 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -62,6 +62,7 @@ import haveno.core.offer.messages.SignOfferResponse; import haveno.core.offer.placeoffer.PlaceOfferModel; import haveno.core.offer.placeoffer.PlaceOfferProtocol; +import haveno.core.offer.placeoffer.tasks.ValidateOffer; import haveno.core.provider.price.PriceFeedService; import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; @@ -934,6 +935,14 @@ private void doProcessPendingOffer(List openOffers, OpenOffer openOff return; } + // validate offer + try { + ValidateOffer.validateOffer(openOffer.getOffer(), accountAgeWitnessService, user); + } catch (Exception e) { + errorMessageHandler.handleErrorMessage("Failed to validate offer: " + e.getMessage()); + return; + } + // cancel offer if scheduled txs unavailable if (openOffer.getScheduledTxHashes() != null) { boolean scheduledTxsAvailable = true; diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java index 5f683bacf20..dfb1b2fa34e 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java @@ -19,10 +19,12 @@ import haveno.common.taskrunner.Task; import haveno.common.taskrunner.TaskRunner; +import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.offer.Offer; import haveno.core.offer.placeoffer.PlaceOfferModel; import haveno.core.trade.HavenoUtils; import haveno.core.trade.messages.TradeMessage; +import haveno.core.user.User; import org.bitcoinj.core.Coin; import java.math.BigInteger; @@ -41,55 +43,7 @@ protected void run() { try { runInterceptHook(); - // Coins - checkBINotNullOrZero(offer.getAmount(), "Amount"); - checkBINotNullOrZero(offer.getMinAmount(), "MinAmount"); - //checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model - checkBINotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit"); - if (offer.getMakerFeePct() < 0) throw new IllegalArgumentException("Maker fee must be >= 0% but was " + offer.getMakerFeePct()); - if (offer.getTakerFeePct() < 0) throw new IllegalArgumentException("Taker fee must be >= 0% but was " + offer.getTakerFeePct()); - if (offer.getBuyerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Buyer security deposit percent must be positive but was " + offer.getBuyerSecurityDepositPct()); - if (offer.getSellerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Seller security deposit percent must be positive but was " + offer.getSellerSecurityDepositPct()); - - // We remove those checks to be more flexible with future changes. - /*checkArgument(offer.getMakerFee().value >= FeeService.getMinMakerFee(offer.isCurrencyForMakerFeeBtc()).value, - "createOfferFee must not be less than FeeService.MIN_CREATE_OFFER_FEE_IN_BTC. " + - "MakerFee=" + offer.getMakerFee().toFriendlyString());*/ - /*checkArgument(offer.getBuyerSecurityDeposit().value >= ProposalConsensus.getMinBuyerSecurityDeposit().value, - "buyerSecurityDeposit must not be less than ProposalConsensus.MIN_BUYER_SECURITY_DEPOSIT. " + - "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); - checkArgument(offer.getBuyerSecurityDeposit().value <= ProposalConsensus.getMaxBuyerSecurityDeposit().value, - "buyerSecurityDeposit must not be larger than ProposalConsensus.MAX_BUYER_SECURITY_DEPOSIT. " + - "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); - checkArgument(offer.getSellerSecurityDeposit().value == ProposalConsensus.getSellerSecurityDeposit().value, - "sellerSecurityDeposit must be equal to ProposalConsensus.SELLER_SECURITY_DEPOSIT. " + - "sellerSecurityDeposit=" + offer.getSellerSecurityDeposit().toFriendlyString());*/ - /*checkArgument(offer.getMinAmount().compareTo(ProposalConsensus.getMinTradeAmount()) >= 0, - "MinAmount is less than " + ProposalConsensus.getMinTradeAmount().toFriendlyString());*/ - - long maxAmount = model.getAccountAgeWitnessService().getMyTradeLimit(model.getUser().getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection()); - checkArgument(offer.getAmount().longValueExact() <= maxAmount, - "Amount is larger than " + HavenoUtils.atomicUnitsToXmr(offer.getPaymentMethod().getMaxTradeLimit(offer.getCurrencyCode())) + " XMR"); - checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount"); - - checkNotNull(offer.getPrice(), "Price is null"); - if (!offer.isUseMarketBasedPrice()) checkArgument(offer.getPrice().isPositive(), - "Price must be positive unless using market based price. price=" + offer.getPrice().toFriendlyString()); - - checkArgument(offer.getDate().getTime() > 0, - "Date must not be 0. date=" + offer.getDate().toString()); - - checkNotNull(offer.getCurrencyCode(), "Currency is null"); - checkNotNull(offer.getDirection(), "Direction is null"); - checkNotNull(offer.getId(), "Id is null"); - checkNotNull(offer.getPubKeyRing(), "pubKeyRing is null"); - checkNotNull(offer.getMinAmount(), "MinAmount is null"); - checkNotNull(offer.getPrice(), "Price is null"); - checkNotNull(offer.getVersionNr(), "VersionNr is null"); - checkArgument(offer.getMaxTradePeriod() > 0, - "maxTradePeriod must be positive. maxTradePeriod=" + offer.getMaxTradePeriod()); - // TODO check upper and lower bounds for fiat - // TODO check rest of new parameters + validateOffer(offer, model.getAccountAgeWitnessService(), model.getUser()); complete(); } catch (Exception e) { @@ -100,42 +54,95 @@ protected void run() { } } - public static void checkBINotNullOrZero(BigInteger value, String name) { + public static void validateOffer(Offer offer, AccountAgeWitnessService accountAgeWitnessService, User user) { + + // Coins + checkBINotNullOrZero(offer.getAmount(), "Amount"); + checkBINotNullOrZero(offer.getMinAmount(), "MinAmount"); + //checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model + checkBINotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit"); + if (offer.getMakerFeePct() < 0) throw new IllegalArgumentException("Maker fee must be >= 0% but was " + offer.getMakerFeePct()); + if (offer.getTakerFeePct() < 0) throw new IllegalArgumentException("Taker fee must be >= 0% but was " + offer.getTakerFeePct()); + if (offer.getBuyerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Buyer security deposit percent must be positive but was " + offer.getBuyerSecurityDepositPct()); + if (offer.getSellerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Seller security deposit percent must be positive but was " + offer.getSellerSecurityDepositPct()); + + // We remove those checks to be more flexible with future changes. + /*checkArgument(offer.getMakerFee().value >= FeeService.getMinMakerFee(offer.isCurrencyForMakerFeeBtc()).value, + "createOfferFee must not be less than FeeService.MIN_CREATE_OFFER_FEE_IN_BTC. " + + "MakerFee=" + offer.getMakerFee().toFriendlyString());*/ + /*checkArgument(offer.getBuyerSecurityDeposit().value >= ProposalConsensus.getMinBuyerSecurityDeposit().value, + "buyerSecurityDeposit must not be less than ProposalConsensus.MIN_BUYER_SECURITY_DEPOSIT. " + + "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); + checkArgument(offer.getBuyerSecurityDeposit().value <= ProposalConsensus.getMaxBuyerSecurityDeposit().value, + "buyerSecurityDeposit must not be larger than ProposalConsensus.MAX_BUYER_SECURITY_DEPOSIT. " + + "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); + checkArgument(offer.getSellerSecurityDeposit().value == ProposalConsensus.getSellerSecurityDeposit().value, + "sellerSecurityDeposit must be equal to ProposalConsensus.SELLER_SECURITY_DEPOSIT. " + + "sellerSecurityDeposit=" + offer.getSellerSecurityDeposit().toFriendlyString());*/ + /*checkArgument(offer.getMinAmount().compareTo(ProposalConsensus.getMinTradeAmount()) >= 0, + "MinAmount is less than " + ProposalConsensus.getMinTradeAmount().toFriendlyString());*/ + + long maxAmount = accountAgeWitnessService.getMyTradeLimit(user.getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection()); + checkArgument(offer.getAmount().longValueExact() <= maxAmount, + "Amount is larger than " + HavenoUtils.atomicUnitsToXmr(offer.getPaymentMethod().getMaxTradeLimit(offer.getCurrencyCode())) + " XMR"); + checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount"); + + checkNotNull(offer.getPrice(), "Price is null"); + if (!offer.isUseMarketBasedPrice()) checkArgument(offer.getPrice().isPositive(), + "Price must be positive unless using market based price. price=" + offer.getPrice().toFriendlyString()); + + checkArgument(offer.getDate().getTime() > 0, + "Date must not be 0. date=" + offer.getDate().toString()); + + checkNotNull(offer.getCurrencyCode(), "Currency is null"); + checkNotNull(offer.getDirection(), "Direction is null"); + checkNotNull(offer.getId(), "Id is null"); + checkNotNull(offer.getPubKeyRing(), "pubKeyRing is null"); + checkNotNull(offer.getMinAmount(), "MinAmount is null"); + checkNotNull(offer.getPrice(), "Price is null"); + checkNotNull(offer.getVersionNr(), "VersionNr is null"); + checkArgument(offer.getMaxTradePeriod() > 0, + "maxTradePeriod must be positive. maxTradePeriod=" + offer.getMaxTradePeriod()); + // TODO check upper and lower bounds for fiat + // TODO check rest of new parameters + } + + private static void checkBINotNullOrZero(BigInteger value, String name) { checkNotNull(value, name + " is null"); checkArgument(value.compareTo(BigInteger.ZERO) > 0, name + " must be positive. " + name + "=" + value); } - public static void checkCoinNotNullOrZero(Coin value, String name) { + private static void checkCoinNotNullOrZero(Coin value, String name) { checkNotNull(value, name + " is null"); checkArgument(value.isPositive(), name + " must be positive. " + name + "=" + value.toFriendlyString()); } - public static String nonEmptyStringOf(String value) { + private static String nonEmptyStringOf(String value) { checkNotNull(value); checkArgument(value.length() > 0); return value; } - public static long nonNegativeLongOf(long value) { + private static long nonNegativeLongOf(long value) { checkArgument(value >= 0); return value; } - public static Coin nonZeroCoinOf(Coin value) { + private static Coin nonZeroCoinOf(Coin value) { checkNotNull(value); checkArgument(!value.isZero()); return value; } - public static Coin positiveCoinOf(Coin value) { + private static Coin positiveCoinOf(Coin value) { checkNotNull(value); checkArgument(value.isPositive()); return value; } - public static void checkTradeId(String tradeId, TradeMessage tradeMessage) { + private static void checkTradeId(String tradeId, TradeMessage tradeMessage) { checkArgument(tradeId.equals(tradeMessage.getOfferId())); } }