diff --git a/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java b/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java index 28d5a1cfb8..b279f68b8e 100644 --- a/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java @@ -189,7 +189,7 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { protected final Function toTradeFeeBtc = (t) -> { var isMyOffer = t.getOffer().getIsMyOffer(); if (isMyOffer) { - return t.getOffer().getMakerFee(); + return t.getMakerFee(); } else { return t.getTakerFee(); } @@ -198,7 +198,7 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { protected final Function toMyMakerOrTakerFee = (t) -> { return isTaker.test(t) ? t.getTakerFee() - : t.getOffer().getMakerFee(); + : t.getMakerFee(); }; protected final Function toOfferType = (t) -> { diff --git a/core/src/main/java/haveno/core/api/CoreTradesService.java b/core/src/main/java/haveno/core/api/CoreTradesService.java index 6f709c1ef4..16fa22a8db 100644 --- a/core/src/main/java/haveno/core/api/CoreTradesService.java +++ b/core/src/main/java/haveno/core/api/CoreTradesService.java @@ -143,18 +143,15 @@ class CoreTradesService { } // synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model - BigInteger takerFee; BigInteger fundsNeededForTrade; synchronized (takeOfferModel) { takeOfferModel.initModel(offer, paymentAccount, amount, useSavingsWallet); - takerFee = takeOfferModel.getTakerFee(); fundsNeededForTrade = takeOfferModel.getFundsNeededForTrade(); log.debug("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel); } // take offer tradeManager.onTakeOffer(amount, - takerFee, fundsNeededForTrade, offer, paymentAccountId, diff --git a/core/src/main/java/haveno/core/api/model/OfferInfo.java b/core/src/main/java/haveno/core/api/model/OfferInfo.java index 7313e1eb95..b489aaa8bb 100644 --- a/core/src/main/java/haveno/core/api/model/OfferInfo.java +++ b/core/src/main/java/haveno/core/api/model/OfferInfo.java @@ -52,8 +52,9 @@ public class OfferInfo implements Payload { private final long minAmount; private final String volume; private final String minVolume; - private final long makerFee; - @Nullable + private final double makerFeePct; + private final double takerFeePct; + private final double penaltyFeePct; private final double buyerSecurityDepositPct; private final double sellerSecurityDepositPct; private final String triggerPrice; @@ -86,11 +87,13 @@ public class OfferInfo implements Payload { this.marketPriceMarginPct = builder.getMarketPriceMarginPct(); this.amount = builder.getAmount(); this.minAmount = builder.getMinAmount(); - this.volume = builder.getVolume(); - this.minVolume = builder.getMinVolume(); - this.makerFee = builder.getMakerFee(); + this.makerFeePct = builder.getMakerFeePct(); + this.takerFeePct = builder.getTakerFeePct(); + this.penaltyFeePct = builder.getPenaltyFeePct(); this.buyerSecurityDepositPct = builder.getBuyerSecurityDepositPct(); this.sellerSecurityDepositPct = builder.getSellerSecurityDepositPct(); + this.volume = builder.getVolume(); + this.minVolume = builder.getMinVolume(); this.triggerPrice = builder.getTriggerPrice(); this.paymentAccountId = builder.getPaymentAccountId(); this.paymentMethodId = builder.getPaymentMethodId(); @@ -155,11 +158,14 @@ public class OfferInfo implements Payload { .withMarketPriceMarginPct(marketPriceMarginAsPctLiteral) .withAmount(offer.getAmount().longValueExact()) .withMinAmount(offer.getMinAmount().longValueExact()) - .withVolume(roundedVolume) - .withMinVolume(roundedMinVolume) - .withMakerFee(offer.getMakerFee().longValueExact()) + .withMakerFeePct(offer.getMakerFeePct()) + .withTakerFeePct(offer.getTakerFeePct()) + .withPenaltyFeePct(offer.getPenaltyFeePct()) + .withSellerSecurityDepositPct(offer.getSellerSecurityDepositPct()) .withBuyerSecurityDepositPct(offer.getBuyerSecurityDepositPct()) .withSellerSecurityDepositPct(offer.getSellerSecurityDepositPct()) + .withVolume(roundedVolume) + .withMinVolume(roundedMinVolume) .withPaymentAccountId(offer.getMakerPaymentAccountId()) .withPaymentMethodId(offer.getPaymentMethod().getId()) .withPaymentMethodShortName(offer.getPaymentMethod().getShortName()) @@ -190,7 +196,9 @@ public class OfferInfo implements Payload { .setMinAmount(minAmount) .setVolume(volume) .setMinVolume(minVolume) - .setMakerFee(makerFee) + .setMakerFeePct(makerFeePct) + .setTakerFeePct(takerFeePct) + .setPenaltyFeePct(penaltyFeePct) .setBuyerSecurityDepositPct(buyerSecurityDepositPct) .setSellerSecurityDepositPct(sellerSecurityDepositPct) .setTriggerPrice(triggerPrice == null ? "0" : triggerPrice) @@ -225,7 +233,9 @@ public class OfferInfo implements Payload { .withMinAmount(proto.getMinAmount()) .withVolume(proto.getVolume()) .withMinVolume(proto.getMinVolume()) - .withMakerFee(proto.getMakerFee()) + .withMakerFeePct(proto.getMakerFeePct()) + .withTakerFeePct(proto.getTakerFeePct()) + .withPenaltyFeePct(proto.getPenaltyFeePct()) .withBuyerSecurityDepositPct(proto.getBuyerSecurityDepositPct()) .withSellerSecurityDepositPct(proto.getSellerSecurityDepositPct()) .withTriggerPrice(proto.getTriggerPrice()) diff --git a/core/src/main/java/haveno/core/api/model/TradeInfo.java b/core/src/main/java/haveno/core/api/model/TradeInfo.java index 8b2a4c79b0..f53d3ee965 100644 --- a/core/src/main/java/haveno/core/api/model/TradeInfo.java +++ b/core/src/main/java/haveno/core/api/model/TradeInfo.java @@ -64,11 +64,12 @@ public class TradeInfo implements Payload { private final String shortId; private final long date; private final String role; - private final long takerFee; private final String makerDepositTxId; private final String takerDepositTxId; private final String payoutTxId; private final long amount; + private final long makerFee; + private final long takerFee; private final long buyerSecurityDeposit; private final long sellerSecurityDeposit; private final long buyerDepositTxFee; @@ -104,11 +105,12 @@ public class TradeInfo implements Payload { this.shortId = builder.getShortId(); this.date = builder.getDate(); this.role = builder.getRole(); - this.takerFee = builder.getTakerFee(); this.makerDepositTxId = builder.getMakerDepositTxId(); this.takerDepositTxId = builder.getTakerDepositTxId(); this.payoutTxId = builder.getPayoutTxId(); this.amount = builder.getAmount(); + this.makerFee = builder.getMakerFee(); + this.takerFee = builder.getTakerFee(); this.buyerSecurityDeposit = builder.getBuyerSecurityDeposit(); this.sellerSecurityDeposit = builder.getSellerSecurityDeposit(); this.buyerDepositTxFee = builder.getBuyerDepositTxFee(); @@ -166,11 +168,12 @@ public class TradeInfo implements Payload { .withShortId(trade.getShortId()) .withDate(trade.getDate().getTime()) .withRole(role == null ? "" : role) - .withTakerFee(trade.getTakerFee().longValueExact()) .withMakerDepositTxId(trade.getMaker().getDepositTxHash()) .withTakerDepositTxId(trade.getTaker().getDepositTxHash()) .withPayoutTxId(trade.getPayoutTxId()) .withAmount(trade.getAmount().longValueExact()) + .withMakerFee(trade.getMakerFee().longValueExact()) + .withTakerFee(trade.getTakerFee().longValueExact()) .withBuyerSecurityDeposit(trade.getBuyer().getSecurityDeposit() == null ? -1 : trade.getBuyer().getSecurityDeposit().longValueExact()) .withSellerSecurityDeposit(trade.getSeller().getSecurityDeposit() == null ? -1 : trade.getSeller().getSecurityDeposit().longValueExact()) .withBuyerDepositTxFee(trade.getBuyer().getDepositTxFee() == null ? -1 : trade.getBuyer().getDepositTxFee().longValueExact()) @@ -216,11 +219,12 @@ public class TradeInfo implements Payload { .setShortId(shortId) .setDate(date) .setRole(role) - .setTakerFee(takerFee) .setMakerDepositTxId(makerDepositTxId == null ? "" : makerDepositTxId) .setTakerDepositTxId(takerDepositTxId == null ? "" : takerDepositTxId) .setPayoutTxId(payoutTxId == null ? "" : payoutTxId) .setAmount(amount) + .setMakerFee(makerFee) + .setTakerFee(takerFee) .setBuyerSecurityDeposit(buyerSecurityDeposit) .setSellerSecurityDeposit(sellerSecurityDeposit) .setBuyerDepositTxFee(buyerDepositTxFee) @@ -259,11 +263,12 @@ public class TradeInfo implements Payload { .withShortId(proto.getShortId()) .withDate(proto.getDate()) .withRole(proto.getRole()) - .withTakerFee(proto.getTakerFee()) .withMakerDepositTxId(proto.getMakerDepositTxId()) .withTakerDepositTxId(proto.getTakerDepositTxId()) .withPayoutTxId(proto.getPayoutTxId()) .withAmount(proto.getAmount()) + .withMakerFee(proto.getMakerFee()) + .withTakerFee(proto.getTakerFee()) .withBuyerSecurityDeposit(proto.getBuyerSecurityDeposit()) .withSellerSecurityDeposit(proto.getSellerSecurityDeposit()) .withBuyerDepositTxFee(proto.getBuyerDepositTxFee()) @@ -302,11 +307,12 @@ public class TradeInfo implements Payload { ", shortId='" + shortId + '\'' + "\n" + ", date='" + date + '\'' + "\n" + ", role='" + role + '\'' + "\n" + - ", takerFee='" + takerFee + '\'' + "\n" + ", makerDepositTxId='" + makerDepositTxId + '\'' + "\n" + ", takerDepositTxId='" + takerDepositTxId + '\'' + "\n" + ", payoutTxId='" + payoutTxId + '\'' + "\n" + ", amount='" + amount + '\'' + "\n" + + ", makerFee='" + makerFee + '\'' + "\n" + + ", takerFee='" + takerFee + '\'' + "\n" + ", buyerSecurityDeposit='" + buyerSecurityDeposit + '\'' + "\n" + ", sellerSecurityDeposit='" + sellerSecurityDeposit + '\'' + "\n" + ", buyerDepositTxFee='" + buyerDepositTxFee + '\'' + "\n" + diff --git a/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java b/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java index e202589931..35d532f67f 100644 --- a/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java +++ b/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java @@ -38,7 +38,9 @@ public final class OfferInfoBuilder { private long minAmount; private String volume; private String minVolume; - private long makerFee; + private double makerFeePct; + private double takerFeePct; + private double penaltyFeePct; private double buyerSecurityDepositPct; private double sellerSecurityDepositPct; private String triggerPrice; @@ -97,18 +99,18 @@ public final class OfferInfoBuilder { return this; } - public OfferInfoBuilder withVolume(String volume) { - this.volume = volume; + public OfferInfoBuilder withMakerFeePct(double makerFeePct) { + this.makerFeePct = makerFeePct; return this; } - public OfferInfoBuilder withMinVolume(String minVolume) { - this.minVolume = minVolume; + public OfferInfoBuilder withTakerFeePct(double takerFeePct) { + this.takerFeePct = takerFeePct; return this; } - public OfferInfoBuilder withMakerFee(long makerFee) { - this.makerFee = makerFee; + public OfferInfoBuilder withPenaltyFeePct(double penaltyFeePct) { + this.penaltyFeePct = penaltyFeePct; return this; } @@ -122,6 +124,16 @@ public final class OfferInfoBuilder { return this; } + public OfferInfoBuilder withVolume(String volume) { + this.volume = volume; + return this; + } + + public OfferInfoBuilder withMinVolume(String minVolume) { + this.minVolume = minVolume; + return this; + } + public OfferInfoBuilder withTriggerPrice(String triggerPrice) { this.triggerPrice = triggerPrice; return this; diff --git a/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java b/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java index 59fac642a9..dcf40b8a69 100644 --- a/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java +++ b/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java @@ -38,6 +38,7 @@ public final class TradeInfoV1Builder { private String role; private boolean isCurrencyForTakerFeeBtc; private long totalTxFee; + private long makerFee; private long takerFee; private long buyerSecurityDeposit; private long sellerSecurityDeposit; @@ -108,6 +109,11 @@ public final class TradeInfoV1Builder { return this; } + public TradeInfoV1Builder withMakerFee(long makerFee) { + this.makerFee = makerFee; + return this; + } + public TradeInfoV1Builder withTakerFee(long takerFee) { this.takerFee = takerFee; return this; diff --git a/core/src/main/java/haveno/core/offer/CreateOfferService.java b/core/src/main/java/haveno/core/offer/CreateOfferService.java index 59d3790f55..f79c4c7f56 100644 --- a/core/src/main/java/haveno/core/offer/CreateOfferService.java +++ b/core/src/main/java/haveno/core/offer/CreateOfferService.java @@ -160,7 +160,6 @@ public class CreateOfferService { List acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount); String bankId = PaymentAccountUtil.getBankId(paymentAccount); List acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount); - BigInteger makerFee = HavenoUtils.getMakerFee(amount); long maxTradePeriod = paymentAccount.getMaxTradePeriod(); // reserved for future use cases @@ -178,8 +177,7 @@ public class CreateOfferService { offerUtil.validateOfferData( securityDepositAsDouble, paymentAccount, - currencyCode, - makerFee); + currencyCode); OfferPayload offerPayload = new OfferPayload(offerId, creationTime, @@ -191,6 +189,11 @@ public class CreateOfferService { useMarketBasedPriceValue, amountAsLong, minAmountAsLong, + HavenoUtils.MAKER_FEE_PCT, + HavenoUtils.TAKER_FEE_PCT, + HavenoUtils.PENALTY_FEE_PCT, + securityDepositAsDouble, + securityDepositAsDouble, baseCurrencyCode, counterCurrencyCode, paymentAccount.getPaymentMethod().getId(), @@ -201,9 +204,6 @@ public class CreateOfferService { acceptedBanks, Version.VERSION, xmrWalletService.getWallet().getHeight(), - makerFee.longValueExact(), - securityDepositAsDouble, - securityDepositAsDouble, maxTradeLimit, maxTradePeriod, useAutoClose, diff --git a/core/src/main/java/haveno/core/offer/Offer.java b/core/src/main/java/haveno/core/offer/Offer.java index 63bc8aa509..2c73259a7f 100644 --- a/core/src/main/java/haveno/core/offer/Offer.java +++ b/core/src/main/java/haveno/core/offer/Offer.java @@ -39,6 +39,7 @@ import haveno.core.offer.availability.OfferAvailabilityProtocol; import haveno.core.payment.payload.PaymentMethod; import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.PriceFeedService; +import haveno.core.trade.HavenoUtils; import haveno.core.util.VolumeUtil; import haveno.network.p2p.NodeAddress; import javafx.beans.property.ObjectProperty; @@ -285,12 +286,12 @@ public class Offer implements NetworkPayload, PersistablePayload { public BigInteger getReserveAmount() { BigInteger reserveAmount = getDirection() == OfferDirection.BUY ? getMaxBuyerSecurityDeposit() : getMaxSellerSecurityDeposit(); if (getDirection() == OfferDirection.SELL) reserveAmount = reserveAmount.add(getAmount()); - reserveAmount = reserveAmount.add(getMakerFee()); + reserveAmount = reserveAmount.add(getMaxMakerFee()); return reserveAmount; } - public BigInteger getMakerFee() { - return BigInteger.valueOf(offerPayload.getMakerFee()); + public BigInteger getMaxMakerFee() { + return offerPayload.getMaxMakerFee(); } public BigInteger getMaxBuyerSecurityDeposit() { @@ -301,6 +302,26 @@ public class Offer implements NetworkPayload, PersistablePayload { return offerPayload.getMaxSellerSecurityDeposit(); } + public double getMakerFeePct() { + return offerPayload.getMakerFeePct(); + } + + public double getTakerFeePct() { + return offerPayload.getTakerFeePct(); + } + + public double getPenaltyFeePct() { + return offerPayload.getPenaltyFeePct(); + } + + public BigInteger getMakerFee(BigInteger tradeAmount) { + return HavenoUtils.multiply(tradeAmount, getMakerFeePct()); + } + + public BigInteger getTakerFee(BigInteger tradeAmount) { + return HavenoUtils.multiply(tradeAmount, getTakerFeePct()); + } + public double getBuyerSecurityDepositPct() { return offerPayload.getBuyerSecurityDepositPct(); } diff --git a/core/src/main/java/haveno/core/offer/OfferPayload.java b/core/src/main/java/haveno/core/offer/OfferPayload.java index 76e9c8492a..2fa0a2a988 100644 --- a/core/src/main/java/haveno/core/offer/OfferPayload.java +++ b/core/src/main/java/haveno/core/offer/OfferPayload.java @@ -132,7 +132,9 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay @Nullable private final List acceptedBankIds; private final long blockHeightAtOfferCreation; - private final long makerFee; + private final double makerFeePct; + private final double takerFeePct; + private final double penaltyFeePct; private final double buyerSecurityDepositPct; private final double sellerSecurityDepositPct; private final long maxTradeLimit; @@ -168,6 +170,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay boolean useMarketBasedPrice, long amount, long minAmount, + double makerFeePct, + double takerFeePct, + double penaltyFeePct, + double buyerSecurityDepositPct, + double sellerSecurityDepositPct, String baseCurrencyCode, String counterCurrencyCode, String paymentMethodId, @@ -178,9 +185,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay @Nullable List acceptedBankIds, String versionNr, long blockHeightAtOfferCreation, - long makerFee, - double buyerSecurityDepositPct, - double sellerSecurityDepositPct, long maxTradeLimit, long maxTradePeriod, boolean useAutoClose, @@ -204,6 +208,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay this.price = price; this.amount = amount; this.minAmount = minAmount; + this.makerFeePct = makerFeePct; + this.takerFeePct = takerFeePct; + this.penaltyFeePct = penaltyFeePct; + this.buyerSecurityDepositPct = buyerSecurityDepositPct; + this.sellerSecurityDepositPct = sellerSecurityDepositPct; this.paymentMethodId = paymentMethodId; this.makerPaymentAccountId = makerPaymentAccountId; this.extraDataMap = extraDataMap; @@ -219,9 +228,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay this.bankId = bankId; this.acceptedBankIds = acceptedBankIds; this.blockHeightAtOfferCreation = blockHeightAtOfferCreation; - this.makerFee = makerFee; - this.buyerSecurityDepositPct = buyerSecurityDepositPct; - this.sellerSecurityDepositPct = sellerSecurityDepositPct; this.maxTradeLimit = maxTradeLimit; this.maxTradePeriod = maxTradePeriod; this.useAutoClose = useAutoClose; @@ -253,6 +259,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay false, amount, minAmount, + makerFeePct, + takerFeePct, + penaltyFeePct, + buyerSecurityDepositPct, + sellerSecurityDepositPct, baseCurrencyCode, counterCurrencyCode, paymentMethodId, @@ -263,9 +274,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay acceptedBankIds, versionNr, blockHeightAtOfferCreation, - makerFee, - buyerSecurityDepositPct, - sellerSecurityDepositPct, maxTradeLimit, maxTradePeriod, useAutoClose, @@ -303,6 +311,10 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay return getBaseCurrencyCode().equals("XMR") ? getCounterCurrencyCode() : getBaseCurrencyCode(); } + public BigInteger getMaxMakerFee() { + return HavenoUtils.multiply(BigInteger.valueOf(getAmount()), getMakerFeePct()); + } + public BigInteger getMaxBuyerSecurityDeposit() { return getBuyerSecurityDepositForTradeAmount(BigInteger.valueOf(getAmount())); } @@ -312,12 +324,12 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay } public BigInteger getBuyerSecurityDepositForTradeAmount(BigInteger tradeAmount) { - BigInteger securityDepositUnadjusted = HavenoUtils.xmrToAtomicUnits(HavenoUtils.atomicUnitsToXmr(tradeAmount) * getBuyerSecurityDepositPct()); + BigInteger securityDepositUnadjusted = HavenoUtils.multiply(tradeAmount, getBuyerSecurityDepositPct()); return Restrictions.getMinBuyerSecurityDeposit().max(securityDepositUnadjusted); } public BigInteger getSellerSecurityDepositForTradeAmount(BigInteger tradeAmount) { - BigInteger securityDepositUnadjusted = HavenoUtils.xmrToAtomicUnits(HavenoUtils.atomicUnitsToXmr(tradeAmount) * getSellerSecurityDepositPct()); + BigInteger securityDepositUnadjusted = HavenoUtils.multiply(tradeAmount, getSellerSecurityDepositPct()); return Restrictions.getMinSellerSecurityDeposit().max(securityDepositUnadjusted); } @@ -337,15 +349,17 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay .setUseMarketBasedPrice(useMarketBasedPrice) .setAmount(amount) .setMinAmount(minAmount) + .setMakerFeePct(makerFeePct) + .setTakerFeePct(takerFeePct) + .setPenaltyFeePct(penaltyFeePct) + .setBuyerSecurityDepositPct(buyerSecurityDepositPct) + .setSellerSecurityDepositPct(sellerSecurityDepositPct) .setBaseCurrencyCode(baseCurrencyCode) .setCounterCurrencyCode(counterCurrencyCode) .setPaymentMethodId(paymentMethodId) .setMakerPaymentAccountId(makerPaymentAccountId) .setVersionNr(versionNr) .setBlockHeightAtOfferCreation(blockHeightAtOfferCreation) - .setMakerFee(makerFee) - .setBuyerSecurityDepositPct(buyerSecurityDepositPct) - .setSellerSecurityDepositPct(sellerSecurityDepositPct) .setMaxTradeLimit(maxTradeLimit) .setMaxTradePeriod(maxTradePeriod) .setUseAutoClose(useAutoClose) @@ -387,6 +401,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay proto.getUseMarketBasedPrice(), proto.getAmount(), proto.getMinAmount(), + proto.getMakerFeePct(), + proto.getTakerFeePct(), + proto.getPenaltyFeePct(), + proto.getBuyerSecurityDepositPct(), + proto.getSellerSecurityDepositPct(), proto.getBaseCurrencyCode(), proto.getCounterCurrencyCode(), proto.getPaymentMethodId(), @@ -397,9 +416,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay acceptedBankIds, proto.getVersionNr(), proto.getBlockHeightAtOfferCreation(), - proto.getMakerFee(), - proto.getBuyerSecurityDepositPct(), - proto.getSellerSecurityDepositPct(), proto.getMaxTradeLimit(), proto.getMaxTradePeriod(), proto.getUseAutoClose(), @@ -425,6 +441,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay ",\r\n price=" + price + ",\r\n amount=" + amount + ",\r\n minAmount=" + minAmount + + ",\r\n makerFeePct=" + makerFeePct + + ",\r\n takerFeePct=" + takerFeePct + + ",\r\n penaltyFeePct=" + penaltyFeePct + + ",\r\n buyerSecurityDepositPct=" + buyerSecurityDepositPct + + ",\r\n sellerSecurityDeposiPct=" + sellerSecurityDepositPct + ",\r\n paymentMethodId='" + paymentMethodId + '\'' + ",\r\n makerPaymentAccountId='" + makerPaymentAccountId + '\'' + ",\r\n ownerNodeAddress=" + ownerNodeAddress + @@ -442,9 +463,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay ",\r\n bankId='" + bankId + '\'' + ",\r\n acceptedBankIds=" + acceptedBankIds + ",\r\n blockHeightAtOfferCreation=" + blockHeightAtOfferCreation + - ",\r\n makerFee=" + makerFee + - ",\r\n buyerSecurityDepositPct=" + buyerSecurityDepositPct + - ",\r\n sellerSecurityDeposiPct=" + sellerSecurityDepositPct + ",\r\n maxTradeLimit=" + maxTradeLimit + ",\r\n maxTradePeriod=" + maxTradePeriod + ",\r\n useAutoClose=" + useAutoClose + @@ -474,15 +492,17 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay object.add("useMarketBasedPrice", context.serialize(offerPayload.isUseMarketBasedPrice())); object.add("amount", context.serialize(offerPayload.getAmount())); object.add("minAmount", context.serialize(offerPayload.getMinAmount())); + object.add("makerFeePct", context.serialize(offerPayload.getMakerFeePct())); + object.add("takerFeePct", context.serialize(offerPayload.getTakerFeePct())); + object.add("penaltyFeePct", context.serialize(offerPayload.getPenaltyFeePct())); + object.add("buyerSecurityDepositPct", context.serialize(offerPayload.getBuyerSecurityDepositPct())); + object.add("sellerSecurityDepositPct", context.serialize(offerPayload.getSellerSecurityDepositPct())); object.add("baseCurrencyCode", context.serialize(offerPayload.getBaseCurrencyCode())); object.add("counterCurrencyCode", context.serialize(offerPayload.getCounterCurrencyCode())); object.add("paymentMethodId", context.serialize(offerPayload.getPaymentMethodId())); object.add("makerPaymentAccountId", context.serialize(offerPayload.getMakerPaymentAccountId())); object.add("versionNr", context.serialize(offerPayload.getVersionNr())); object.add("blockHeightAtOfferCreation", context.serialize(offerPayload.getBlockHeightAtOfferCreation())); - object.add("makerFee", context.serialize(offerPayload.getMakerFee())); - object.add("buyerSecurityDepositPct", context.serialize(offerPayload.getBuyerSecurityDepositPct())); - object.add("sellerSecurityDepositPct", context.serialize(offerPayload.getSellerSecurityDepositPct())); object.add("maxTradeLimit", context.serialize(offerPayload.getMaxTradeLimit())); object.add("maxTradePeriod", context.serialize(offerPayload.getMaxTradePeriod())); object.add("useAutoClose", context.serialize(offerPayload.isUseAutoClose())); diff --git a/core/src/main/java/haveno/core/offer/OfferUtil.java b/core/src/main/java/haveno/core/offer/OfferUtil.java index 081198770f..b6039fd279 100644 --- a/core/src/main/java/haveno/core/offer/OfferUtil.java +++ b/core/src/main/java/haveno/core/offer/OfferUtil.java @@ -211,9 +211,7 @@ public class OfferUtil { public void validateOfferData(double buyerSecurityDeposit, PaymentAccount paymentAccount, - String currencyCode, - BigInteger makerFee) { - checkNotNull(makerFee, "makerFee must not be null"); + String currencyCode) { checkNotNull(p2PService.getAddress(), "Address must not be null"); checkArgument(buyerSecurityDeposit <= getMaxBuyerSecurityDepositAsPercent(), "securityDeposit must not exceed " + diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index a032ab42aa..3fbaaeb4e5 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -538,7 +538,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe boolean reserveExactAmount, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - checkNotNull(offer.getMakerFee(), "makerFee must not be null"); // create open offer OpenOffer openOffer = new OpenOffer(offer, triggerPrice, reserveExactAmount); @@ -1199,9 +1198,24 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // verify maker's trade fee Offer offer = new Offer(request.getOfferPayload()); - BigInteger tradeFee = HavenoUtils.getMakerFee(offer.getAmount()); - if (!tradeFee.equals(offer.getMakerFee())) { - errorMessage = "Wrong trade fee for offer " + request.offerId; + if (offer.getMakerFeePct() != HavenoUtils.MAKER_FEE_PCT) { + errorMessage = "Wrong maker fee for offer " + request.offerId; + log.info(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify taker's trade fee + if (offer.getTakerFeePct() != HavenoUtils.TAKER_FEE_PCT) { + errorMessage = "Wrong taker fee for offer " + request.offerId; + log.info(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify penalty fee + if (offer.getPenaltyFeePct() != HavenoUtils.PENALTY_FEE_PCT) { + errorMessage = "Wrong penalty fee for offer " + request.offerId; log.info(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; @@ -1216,11 +1230,14 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } // verify maker's reserve tx (double spend, trade fee, trade amount, mining fee) + BigInteger penaltyFee = HavenoUtils.multiply(offer.getAmount(), HavenoUtils.PENALTY_FEE_PCT); + BigInteger maxTradeFee = HavenoUtils.multiply(offer.getAmount(), HavenoUtils.MAKER_FEE_PCT); BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.ZERO : offer.getAmount(); BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit(); Tuple2 txResult = xmrWalletService.verifyTradeTx( offer.getId(), - tradeFee, + penaltyFee, + maxTradeFee, sendAmount, securityDeposit, request.getPayoutAddress(), @@ -1240,7 +1257,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe signedOfferPayload.getPubKeyRing().hashCode(), // trader id signedOfferPayload.getId(), offer.getAmount().longValueExact(), - tradeFee.longValueExact(), + maxTradeFee.longValueExact(), request.getReserveTxHash(), request.getReserveTxHex(), request.getReserveTxKeyImages(), @@ -1549,6 +1566,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe originalOfferPayload.isUseMarketBasedPrice(), originalOfferPayload.getAmount(), originalOfferPayload.getMinAmount(), + originalOfferPayload.getMakerFeePct(), + originalOfferPayload.getTakerFeePct(), + originalOfferPayload.getPenaltyFeePct(), + originalOfferPayload.getBuyerSecurityDepositPct(), + originalOfferPayload.getSellerSecurityDepositPct(), originalOfferPayload.getBaseCurrencyCode(), originalOfferPayload.getCounterCurrencyCode(), originalOfferPayload.getPaymentMethodId(), @@ -1559,9 +1581,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe originalOfferPayload.getAcceptedBankIds(), originalOfferPayload.getVersionNr(), originalOfferPayload.getBlockHeightAtOfferCreation(), - originalOfferPayload.getMakerFee(), - originalOfferPayload.getBuyerSecurityDepositPct(), - originalOfferPayload.getSellerSecurityDepositPct(), originalOfferPayload.getMaxTradeLimit(), originalOfferPayload.getMaxTradePeriod(), originalOfferPayload.isUseAutoClose(), diff --git a/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java b/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java index f726a31d30..dc203bc3cd 100644 --- a/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java +++ b/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java @@ -71,7 +71,6 @@ public class SendOfferAvailabilityRequest extends Task { p2PService.getKeyRing().getPubKeyRing(), model.getTradeAmount().longValueExact(), price.getValue(), - HavenoUtils.getTakerFee(model.getTradeAmount()).longValueExact(), user.getAccountId(), paymentAccountId, paymentMethodId, diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java index 2b1ddfabe8..d4ad40288e 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java @@ -22,6 +22,7 @@ import haveno.common.taskrunner.TaskRunner; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; import haveno.core.offer.placeoffer.PlaceOfferModel; +import haveno.core.trade.HavenoUtils; import haveno.core.xmr.model.XmrAddressEntry; import lombok.extern.slf4j.Slf4j; import monero.daemon.model.MoneroOutput; @@ -50,13 +51,14 @@ public class MakerReserveOfferFunds extends Task { model.getXmrWalletService().getConnectionService().verifyConnection(); // create reserve tx - BigInteger makerFee = offer.getMakerFee(); + BigInteger penaltyFee = HavenoUtils.multiply(offer.getAmount(), offer.getPenaltyFeePct()); + BigInteger makerFee = offer.getMaxMakerFee(); BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.ZERO : offer.getAmount(); BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit(); String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); XmrAddressEntry fundingEntry = model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).orElse(null); Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex(); - MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(makerFee, sendAmount, securityDeposit, returnAddress, model.getOpenOffer().isReserveExactAmount(), preferredSubaddressIndex); + MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, model.getOpenOffer().isReserveExactAmount(), preferredSubaddressIndex); // check for error in case creating reserve tx exceeded timeout // TODO: better way? if (!model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).isPresent()) { 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 795fef6a05..5f683bacf2 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 @@ -44,11 +44,12 @@ public class ValidateOffer extends Task { // Coins checkBINotNullOrZero(offer.getAmount(), "Amount"); checkBINotNullOrZero(offer.getMinAmount(), "MinAmount"); - checkBINotNullOrZero(offer.getMakerFee(), "MakerFee"); //checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model checkBINotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit"); - if (offer.getBuyerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Buyer security deposit must be positive but was " + offer.getBuyerSecurityDepositPct()); - if (offer.getSellerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Seller security deposit must be positive but was " + offer.getSellerSecurityDepositPct()); + 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, @@ -84,7 +85,6 @@ public class ValidateOffer extends Task { checkNotNull(offer.getPubKeyRing(), "pubKeyRing is null"); checkNotNull(offer.getMinAmount(), "MinAmount is null"); checkNotNull(offer.getPrice(), "Price is null"); - checkNotNull(offer.getMakerFee(), "MakerFee is null"); checkNotNull(offer.getVersionNr(), "VersionNr is null"); checkArgument(offer.getMaxTradePeriod() > 0, "maxTradePeriod must be positive. maxTradePeriod=" + offer.getMaxTradePeriod()); @@ -136,6 +136,6 @@ public class ValidateOffer extends Task { } public static void checkTradeId(String tradeId, TradeMessage tradeMessage) { - checkArgument(tradeId.equals(tradeMessage.getTradeId())); + checkArgument(tradeId.equals(tradeMessage.getOfferId())); } } diff --git a/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java b/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java index bfe3b824d9..85d0b99bcf 100644 --- a/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java +++ b/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java @@ -100,7 +100,7 @@ public class TakeOfferModel implements Model { this.securityDeposit = offer.getDirection() == SELL ? offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(amount) : offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(amount); - this.takerFee = HavenoUtils.getTakerFee(amount); + this.takerFee = HavenoUtils.multiply(amount, offer.getTakerFeePct()); calculateVolume(); calculateTotalToPay(); diff --git a/core/src/main/java/haveno/core/trade/ArbitratorTrade.java b/core/src/main/java/haveno/core/trade/ArbitratorTrade.java index b4be6435dc..93f03dece5 100644 --- a/core/src/main/java/haveno/core/trade/ArbitratorTrade.java +++ b/core/src/main/java/haveno/core/trade/ArbitratorTrade.java @@ -36,7 +36,6 @@ public class ArbitratorTrade extends Trade { public ArbitratorTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -44,7 +43,7 @@ public class ArbitratorTrade extends Trade { NodeAddress makerNodeAddress, NodeAddress takerNodeAddress, NodeAddress arbitratorNodeAddress) { - super(offer, tradeAmount, takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, arbitratorNodeAddress); + super(offer, tradeAmount, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, arbitratorNodeAddress); } @Override @@ -76,7 +75,6 @@ public class ArbitratorTrade extends Trade { return fromProto(new ArbitratorTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, diff --git a/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java b/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java index 11e8887831..99fad94ebe 100644 --- a/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java +++ b/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java @@ -37,7 +37,6 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade { public BuyerAsMakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takeOfferFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -47,7 +46,6 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade { NodeAddress arbitratorNodeAddress) { super(offer, tradeAmount, - takeOfferFee, tradePrice, xmrWalletService, processModel, @@ -81,7 +79,6 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade { BuyerAsMakerTrade trade = new BuyerAsMakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, diff --git a/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java b/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java index 869d6c55e2..1cb7b20d47 100644 --- a/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java +++ b/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java @@ -38,7 +38,6 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade { public BuyerAsTakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -48,7 +47,6 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade { @Nullable NodeAddress arbitratorNodeAddress) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, @@ -83,7 +81,6 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade { return fromProto(new BuyerAsTakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, diff --git a/core/src/main/java/haveno/core/trade/BuyerTrade.java b/core/src/main/java/haveno/core/trade/BuyerTrade.java index d86e763492..dbf73db101 100644 --- a/core/src/main/java/haveno/core/trade/BuyerTrade.java +++ b/core/src/main/java/haveno/core/trade/BuyerTrade.java @@ -32,7 +32,6 @@ import static com.google.common.base.Preconditions.checkNotNull; public abstract class BuyerTrade extends Trade { BuyerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -42,7 +41,6 @@ public abstract class BuyerTrade extends Trade { @Nullable NodeAddress arbitratorNodeAddress) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, diff --git a/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java b/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java index ea809e2710..9b9df16d04 100644 --- a/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java +++ b/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java @@ -106,7 +106,7 @@ public class CleanupMailboxMessages { } private boolean isMyMessage(TradeMessage message, Trade trade) { - return message.getTradeId().equals(trade.getId()); + return message.getOfferId().equals(trade.getId()); } private boolean isMyMessage(AckMessage ackMessage, Trade trade) { diff --git a/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java b/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java index 6e2610c0d9..a2b5cde8d7 100644 --- a/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java +++ b/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java @@ -105,7 +105,7 @@ public class CleanupMailboxMessagesService { } private boolean isMyMessage(TradeMessage message, Trade trade) { - return message.getTradeId().equals(trade.getId()); + return message.getOfferId().equals(trade.getId()); } private boolean isMyMessage(AckMessage ackMessage, Trade trade) { diff --git a/core/src/main/java/haveno/core/trade/HavenoUtils.java b/core/src/main/java/haveno/core/trade/HavenoUtils.java index 5843811f2f..8fcbd371cd 100644 --- a/core/src/main/java/haveno/core/trade/HavenoUtils.java +++ b/core/src/main/java/haveno/core/trade/HavenoUtils.java @@ -34,11 +34,9 @@ import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.messages.PaymentReceivedMessage; import haveno.core.trade.messages.PaymentSentMessage; import haveno.core.util.JsonUtil; -import haveno.core.util.ParsingUtils; import haveno.network.p2p.NodeAddress; import java.math.BigDecimal; import java.math.BigInteger; -import java.math.RoundingMode; import java.net.URI; import java.security.PrivateKey; import java.text.DecimalFormat; @@ -48,7 +46,6 @@ import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.concurrent.CountDownLatch; -import javax.annotation.Nullable; import lombok.extern.slf4j.Slf4j; import monero.common.MoneroRpcConnection; import monero.wallet.model.MoneroDestination; @@ -62,12 +59,17 @@ import org.bitcoinj.core.Coin; @Slf4j public class HavenoUtils { - // configurable + // configure release date private static final String RELEASE_DATE = "01-03-2024 00:00:00"; // optionally set to release date of the network in format dd-mm-yyyy to impose temporary limits, etc. e.g. "01-03-2024 00:00:00" public static final int RELEASE_LIMIT_DAYS = 60; // number of days to limit sell offers to max buy limit for new accounts public static final int WARN_ON_OFFER_EXCEEDS_UNSIGNED_BUY_LIMIT_DAYS = 182; // number of days to warn if sell offer exceeds unsigned buy limit public static final int ARBITRATOR_ACK_TIMEOUT_SECONDS = 15; + // configure fees + public static final double MAKER_FEE_PCT = 0.0015; // 0.15% + public static final double TAKER_FEE_PCT = 0.0075; // 0.75% + public static final double PENALTY_FEE_PCT = 0.02; // 2% + // non-configurable public static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = DecimalFormatSymbols.getInstance(Locale.US); // use the US locale as a base for all DecimalFormats (commas should be omitted from number strings) public static int XMR_SMALLEST_UNIT_EXPONENT = 12; @@ -125,7 +127,7 @@ public class HavenoUtils { } public static long atomicUnitsToCentineros(long atomicUnits) { - return atomicUnits / CENTINEROS_AU_MULTIPLIER; + return atomicUnitsToCentineros(BigInteger.valueOf(atomicUnits)); } public static long atomicUnitsToCentineros(BigInteger atomicUnits) { @@ -149,7 +151,7 @@ public class HavenoUtils { } public static BigInteger xmrToAtomicUnits(double xmr) { - return BigDecimal.valueOf(xmr).setScale(8, RoundingMode.DOWN).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).toBigInteger(); + return new BigDecimal(xmr).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).toBigInteger(); } public static long xmrToCentineros(double xmr) { @@ -161,7 +163,11 @@ public class HavenoUtils { } public static double divide(BigInteger auDividend, BigInteger auDivisor) { - return (double) atomicUnitsToCentineros(auDividend) / (double) atomicUnitsToCentineros(auDivisor); + return atomicUnitsToXmr(auDividend) / atomicUnitsToXmr(auDivisor); + } + + public static BigInteger multiply(BigInteger amount1, double amount2) { + return amount1 == null ? null : new BigDecimal(amount1).multiply(BigDecimal.valueOf(amount2)).toBigInteger(); } // ------------------------- FORMAT UTILS --------------------------------- @@ -221,56 +227,12 @@ public class HavenoUtils { public static BigInteger parseXmr(String input) { if (input == null || input.length() == 0) return BigInteger.ZERO; try { - return xmrToAtomicUnits(new BigDecimal(ParsingUtils.parseNumberStringToDouble(input)).doubleValue()); + return new BigDecimal(input).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).toBigInteger(); } catch (Exception e) { return BigInteger.ZERO; } } - // ------------------------------ FEE UTILS ------------------------------- - - @Nullable - public static BigInteger getMakerFee(@Nullable BigInteger amount) { - if (amount != null) { - BigInteger feePerXmr = getFeePerXmr(HavenoUtils.getMakerFeePerXmr(), amount); - return feePerXmr.max(HavenoUtils.getMinMakerFee()); - } else { - return null; - } - } - - @Nullable - public static BigInteger getTakerFee(@Nullable BigInteger amount) { - if (amount != null) { - BigInteger feePerXmr = HavenoUtils.getFeePerXmr(HavenoUtils.getTakerFeePerXmr(), amount); - return feePerXmr.max(HavenoUtils.getMinTakerFee()); - } else { - return null; - } - } - - private static BigInteger getMakerFeePerXmr() { - return HavenoUtils.xmrToAtomicUnits(0.0015); - } - - public static BigInteger getMinMakerFee() { - return HavenoUtils.xmrToAtomicUnits(0.00005); - } - - private static BigInteger getTakerFeePerXmr() { - return HavenoUtils.xmrToAtomicUnits(0.0075); - } - - public static BigInteger getMinTakerFee() { - return HavenoUtils.xmrToAtomicUnits(0.00005); - } - - public static BigInteger getFeePerXmr(BigInteger feePerXmr, BigInteger amount) { - BigDecimal feePerXmrAsDecimal = feePerXmr == null ? BigDecimal.valueOf(0) : new BigDecimal(feePerXmr); - BigDecimal amountMultiplier = BigDecimal.valueOf(divide(amount == null ? BigInteger.ZERO : amount, HavenoUtils.xmrToAtomicUnits(1.0))); - return feePerXmrAsDecimal.multiply(amountMultiplier).toBigInteger(); - } - // ------------------------ SIGNING AND VERIFYING ------------------------- public static byte[] sign(KeyRing keyRing, String message) { @@ -351,12 +313,11 @@ public class HavenoUtils { // re-create trade request with signed fields InitTradeRequest signedRequest = new InitTradeRequest( - request.getTradeId(), + request.getOfferId(), request.getSenderNodeAddress(), request.getPubKeyRing(), request.getTradeAmount(), request.getTradePrice(), - request.getTradeFee(), request.getAccountId(), request.getPaymentAccountId(), request.getPaymentMethodId(), @@ -380,7 +341,7 @@ public class HavenoUtils { // verify maker signature boolean isSignatureValid = isSignatureValid(makerPubKeyRing, tradeRequestAsJson, signature); if (!isSignatureValid) { - log.warn("Invalid maker signature for trade request: " + request.getTradeId() + " from " + request.getSenderNodeAddress().getAddressForDisplay()); + log.warn("Invalid maker signature for trade request: " + request.getOfferId() + " from " + request.getSenderNodeAddress().getAddressForDisplay()); log.warn("Trade request as json: " + tradeRequestAsJson); log.warn("Maker pub key ring: " + (makerPubKeyRing == null ? null : "...")); log.warn("Maker signature: " + (signature == null ? null : Utilities.bytesAsHexString(signature))); @@ -413,7 +374,7 @@ public class HavenoUtils { } // verify trade id - if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); + if (!trade.getId().equals(message.getOfferId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getOfferId()); } /** @@ -441,7 +402,7 @@ public class HavenoUtils { } // verify trade id - if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); + if (!trade.getId().equals(message.getOfferId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getOfferId()); // verify buyer signature of payment sent message if (message.getPaymentSentMessage() != null) verifyPaymentSentMessage(trade, message.getPaymentSentMessage()); diff --git a/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java b/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java index 690f7300a5..c31c325342 100644 --- a/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java +++ b/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java @@ -38,7 +38,6 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade public SellerAsMakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -48,7 +47,6 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade @Nullable NodeAddress arbitratorNodeAddress) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, @@ -83,7 +81,6 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade SellerAsMakerTrade trade = new SellerAsMakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, diff --git a/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java b/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java index 80812b3cb8..afca9346d1 100644 --- a/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java +++ b/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java @@ -38,7 +38,6 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade public SellerAsTakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -48,7 +47,6 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade @Nullable NodeAddress arbitratorNodeAddress) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, @@ -83,7 +81,6 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade return fromProto(new SellerAsTakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, diff --git a/core/src/main/java/haveno/core/trade/SellerTrade.java b/core/src/main/java/haveno/core/trade/SellerTrade.java index f15e1e1300..457ea10aed 100644 --- a/core/src/main/java/haveno/core/trade/SellerTrade.java +++ b/core/src/main/java/haveno/core/trade/SellerTrade.java @@ -30,7 +30,6 @@ import java.math.BigInteger; public abstract class SellerTrade extends Trade { SellerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -40,7 +39,6 @@ public abstract class SellerTrade extends Trade { @Nullable NodeAddress arbitratorNodeAddress) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, diff --git a/core/src/main/java/haveno/core/trade/Tradable.java b/core/src/main/java/haveno/core/trade/Tradable.java index e59919fed9..1033987cc7 100644 --- a/core/src/main/java/haveno/core/trade/Tradable.java +++ b/core/src/main/java/haveno/core/trade/Tradable.java @@ -65,7 +65,7 @@ public interface Tradable extends PersistablePayload { } default Optional getOptionalMakerFee() { - return asTradeModel().map(Trade::getOffer).map(Offer::getMakerFee).or(() -> Optional.ofNullable(getOffer().getMakerFee())); + return asTradeModel().map(Trade::getMakerFee); } default Optional getOptionalTradePeerNodeAddress() { diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 52d7d877f1..e499a9223f 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -345,7 +345,6 @@ public abstract class Trade implements Tradable, Model { private final ProcessModel processModel; @Getter private final Offer offer; - private final long takerFee; // Added in 1.5.1 @Getter @@ -490,7 +489,6 @@ public abstract class Trade implements Tradable, Model { // maker protected Trade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, @@ -500,7 +498,6 @@ public abstract class Trade implements Tradable, Model { @Nullable NodeAddress arbitratorNodeAddress) { this.offer = offer; this.amount = tradeAmount.longValueExact(); - this.takerFee = takerFee.longValueExact(); this.price = tradePrice; this.xmrWalletService = xmrWalletService; this.xmrConnectionService = xmrWalletService.getConnectionService(); @@ -523,7 +520,6 @@ public abstract class Trade implements Tradable, Model { protected Trade(Offer offer, BigInteger tradeAmount, BigInteger txFee, - BigInteger takerFee, long tradePrice, @Nullable NodeAddress mediatorNodeAddress, // TODO (woodser): remove mediator, refund agent from trade @Nullable NodeAddress refundAgentNodeAddress, @@ -536,7 +532,6 @@ public abstract class Trade implements Tradable, Model { this(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, @@ -552,7 +547,6 @@ public abstract class Trade implements Tradable, Model { protected Trade(Offer offer, BigInteger tradeAmount, Coin txFee, - BigInteger takerFee, long tradePrice, NodeAddress makerNodeAddress, NodeAddress takerNodeAddress, @@ -563,7 +557,6 @@ public abstract class Trade implements Tradable, Model { this(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, @@ -926,7 +919,6 @@ public abstract class Trade implements Tradable, Model { private void forceCloseWallet() { if (wallet != null) { - log.warn("Force closing wallet for {} {}", getClass().getSimpleName(), getId()); xmrWalletService.forceCloseWallet(wallet, wallet.getPath()); wallet = null; } @@ -960,7 +952,7 @@ public abstract class Trade implements Tradable, Model { throw new IllegalStateException("Refusing to delete wallet for " + getClass().getSimpleName() + " " + getId() + " because it has a balance"); } - // force close wallet + // force close wallet without warning forceCloseWallet(); // delete wallet @@ -1138,7 +1130,7 @@ public abstract class Trade implements Tradable, Model { // verify fee is within tolerance by recreating payout tx // TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated? - MoneroTxWallet feeEstimateTx = createPayoutTx();; + MoneroTxWallet feeEstimateTx = createPayoutTx(); BigInteger feeEstimate = feeEstimateTx.getFee(); double feeDiff = payoutTx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); // TODO: use BigDecimal? if (feeDiff > XmrWalletService.MINER_FEE_TOLERANCE) throw new IllegalArgumentException("Miner fee is not within " + (XmrWalletService.MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + payoutTx.getFee()); @@ -1912,11 +1904,11 @@ public abstract class Trade implements Tradable, Model { } public BigInteger getMakerFee() { - return offer.getMakerFee(); + return offer.getMakerFee(getAmount()); } public BigInteger getTakerFee() { - return BigInteger.valueOf(takerFee); + return offer.getTakerFee(getAmount()); } public BigInteger getBuyerSecurityDepositBeforeMiningFee() { @@ -2308,7 +2300,6 @@ public abstract class Trade implements Tradable, Model { public Message toProtoMessage() { protobuf.Trade.Builder builder = protobuf.Trade.newBuilder() .setOffer(offer.toProtoMessage()) - .setTakerFee(takerFee) .setTakeOfferDate(takeOfferDate) .setProcessModel(processModel.toProtoMessage()) .setAmount(amount) @@ -2371,7 +2362,6 @@ public abstract class Trade implements Tradable, Model { public String toString() { return "Trade{" + "\n offer=" + offer + - ",\n takerFee=" + takerFee + ",\n totalTxFee=" + getTotalTxFee() + ",\n takeOfferDate=" + takeOfferDate + ",\n processModel=" + processModel + @@ -2389,7 +2379,6 @@ public abstract class Trade implements Tradable, Model { ",\n counterCurrencyTxId='" + counterCurrencyTxId + '\'' + ",\n counterCurrencyExtraData='" + counterCurrencyExtraData + '\'' + ",\n chatMessages=" + chatMessages + - ",\n takerFee=" + takerFee + ",\n xmrWalletService=" + xmrWalletService + ",\n stateProperty=" + stateProperty + ",\n statePhaseProperty=" + phaseProperty + diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index a8b6af0cd8..3b2c7f950b 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -283,7 +283,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi public void onDirectMessage(DecryptedMessageWithPubKey message, NodeAddress peer) { NetworkEnvelope networkEnvelope = message.getNetworkEnvelope(); if (!(networkEnvelope instanceof TradeMessage)) return; - String tradeId = ((TradeMessage) networkEnvelope).getTradeId(); + String tradeId = ((TradeMessage) networkEnvelope).getOfferId(); ThreadUtils.execute(() -> { if (networkEnvelope instanceof InitTradeRequest) { handleInitTradeRequest((InitTradeRequest) networkEnvelope, peer); @@ -532,10 +532,10 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleInitTradeRequest(InitTradeRequest request, NodeAddress sender) { - log.info("Received InitTradeRequest from {} with tradeId {} and uid {}", sender, request.getTradeId(), request.getUid()); + log.info("Received InitTradeRequest from {} with tradeId {} and uid {}", sender, request.getOfferId(), request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid InitTradeRequest message " + request.toString()); return; @@ -549,19 +549,19 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi Arbitrator thisArbitrator = user.getRegisteredArbitrator(); NodeAddress thisAddress = p2PService.getNetworkNode().getNodeAddress(); if (thisArbitrator == null || !thisArbitrator.getNodeAddress().equals(thisAddress)) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because we are not an arbitrator", sender, request.getTradeId()); + log.warn("Ignoring InitTradeRequest from {} with tradeId {} because we are not an arbitrator", sender, request.getOfferId()); return; } // get offer associated with trade Offer offer = null; for (Offer anOffer : offerBookService.getOffers()) { - if (anOffer.getId().equals(request.getTradeId())) { + if (anOffer.getId().equals(request.getOfferId())) { offer = anOffer; } } if (offer == null) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because offer is not on the books", sender, request.getTradeId()); + log.warn("Ignoring InitTradeRequest from {} with tradeId {} because offer is not on the books", sender, request.getOfferId()); return; } @@ -571,7 +571,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // verify maker is offer owner // TODO (woodser): maker address might change if they disconnect and reconnect, should allow maker address to differ if pubKeyRing is same? if (!offer.getOwnerNodeAddress().equals(request.getMakerNodeAddress())) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because maker is not offer owner", sender, request.getTradeId()); + log.warn("Ignoring InitTradeRequest from {} with tradeId {} because maker is not offer owner", sender, request.getOfferId()); return; } @@ -585,7 +585,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi if (!sender.equals(request.getMakerNodeAddress())) { // send nack if trade already taken - String errMsg = "Trade is already taken, tradeId=" + request.getTradeId(); + String errMsg = "Trade is already taken, tradeId=" + request.getOfferId(); log.warn(errMsg); sendAckMessage(sender, request.getPubKeyRing(), request, false, errMsg); return; @@ -594,17 +594,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // verify request is from taker if (!sender.equals(request.getTakerNodeAddress())) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because request must be from taker when trade is not initialized", sender, request.getTradeId()); + log.warn("Ignoring InitTradeRequest from {} with tradeId {} because request must be from taker when trade is not initialized", sender, request.getOfferId()); return; } - // get expected taker fee - BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(request.getTradeAmount())); - // create arbitrator trade trade = new ArbitratorTrade(offer, BigInteger.valueOf(request.getTradeAmount()), - takerFee, offer.getOfferPayload().getPrice(), xmrWalletService, getNewProcessModel(offer), @@ -614,7 +610,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi request.getArbitratorNodeAddress()); // set reserve tx hash if available - Optional signedOfferOptional = openOfferManager.getSignedOfferById(request.getTradeId()); + Optional signedOfferOptional = openOfferManager.getSignedOfferById(request.getOfferId()); if (signedOfferOptional.isPresent()) { SignedOffer signedOffer = signedOfferOptional.get(); trade.getMaker().setReserveTxHash(signedOffer.getReserveTxHash()); @@ -637,7 +633,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // handle request as maker else { - Optional openOfferOptional = openOfferManager.getOpenOfferById(request.getTradeId()); + Optional openOfferOptional = openOfferManager.getOpenOfferById(request.getOfferId()); if (!openOfferOptional.isPresent()) { return; } @@ -652,28 +648,24 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // verify request is from arbitrator Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(sender); if (arbitrator == null) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because request is not from accepted arbitrator", sender, request.getTradeId()); + log.warn("Ignoring InitTradeRequest from {} with tradeId {} because request is not from accepted arbitrator", sender, request.getOfferId()); return; } - Optional tradeOptional = getOpenTrade(request.getTradeId()); + Optional tradeOptional = getOpenTrade(request.getOfferId()); if (tradeOptional.isPresent()) { - log.warn("Maker trade already exists with id " + request.getTradeId() + ". This should never happen."); + log.warn("Maker trade already exists with id " + request.getOfferId() + ". This should never happen."); return; } // reserve open offer openOfferManager.reserveOpenOffer(openOffer); - // get expected taker fee - BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(request.getTradeAmount())); - // initialize trade Trade trade; if (offer.isBuyOffer()) trade = new BuyerAsMakerTrade(offer, BigInteger.valueOf(request.getTradeAmount()), - takerFee, offer.getOfferPayload().getPrice(), xmrWalletService, getNewProcessModel(offer), @@ -684,7 +676,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi else trade = new SellerAsMakerTrade(offer, BigInteger.valueOf(request.getTradeAmount()), - takerFee, offer.getOfferPayload().getPrice(), xmrWalletService, getNewProcessModel(offer), @@ -720,18 +711,18 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getOfferId(), peer, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid InitMultisigRequest " + request.toString()); return; } - Optional tradeOptional = getOpenTrade(request.getTradeId()); + Optional tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId() + " at node " + P2PService.getMyNodeAddress()); + log.warn("No trade with id " + request.getOfferId() + " at node " + P2PService.getMyNodeAddress()); return; } Trade trade = tradeOptional.get(); @@ -739,18 +730,18 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleSignContractRequest(SignContractRequest request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getOfferId(), peer, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid SignContractRequest message " + request.toString()); return; } - Optional tradeOptional = getOpenTrade(request.getTradeId()); + Optional tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId()); + log.warn("No trade with id " + request.getOfferId()); return; } Trade trade = tradeOptional.get(); @@ -758,18 +749,18 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleSignContractResponse(SignContractResponse request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getOfferId(), peer, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid SignContractResponse message " + request.toString()); return; } - Optional tradeOptional = getOpenTrade(request.getTradeId()); + Optional tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId()); + log.warn("No trade with id " + request.getOfferId()); return; } Trade trade = tradeOptional.get(); @@ -777,18 +768,18 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleDepositRequest(DepositRequest request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getOfferId(), peer, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid DepositRequest message " + request.toString()); return; } - Optional tradeOptional = getOpenTrade(request.getTradeId()); + Optional tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId()); + log.warn("No trade with id " + request.getOfferId()); return; } Trade trade = tradeOptional.get(); @@ -796,18 +787,18 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleDepositResponse(DepositResponse response, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", response.getClass().getSimpleName(), response.getTradeId(), peer, response.getUid()); + log.info("Received {} for trade {} from {} with uid {}", response.getClass().getSimpleName(), response.getOfferId(), peer, response.getUid()); try { - Validator.nonEmptyStringOf(response.getTradeId()); + Validator.nonEmptyStringOf(response.getOfferId()); } catch (Throwable t) { log.warn("Invalid DepositResponse message " + response.toString()); return; } - Optional tradeOptional = getOpenTrade(response.getTradeId()); + Optional tradeOptional = getOpenTrade(response.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + response.getTradeId()); + log.warn("No trade with id " + response.getOfferId()); return; } Trade trade = tradeOptional.get(); @@ -829,7 +820,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // First we check if offer is still available then we create the trade with the protocol public void onTakeOffer(BigInteger amount, - BigInteger takerFee, BigInteger fundsNeededForTrade, Offer offer, String paymentAccountId, @@ -852,7 +842,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi if (offer.isBuyOffer()) { trade = new SellerAsTakerTrade(offer, amount, - takerFee, model.getTradeRequest().getTradePrice(), xmrWalletService, getNewProcessModel(offer), @@ -863,7 +852,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } else { trade = new BuyerAsTakerTrade(offer, amount, - takerFee, model.getTradeRequest().getTradePrice(), xmrWalletService, getNewProcessModel(offer), @@ -1139,7 +1127,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi public void sendAckMessage(NodeAddress peer, PubKeyRing peersPubKeyRing, TradeMessage message, boolean result, @Nullable String errorMessage) { // create ack message - String tradeId = message.getTradeId(); + String tradeId = message.getOfferId(); String sourceUid = message.getUid(); AckMessage ackMessage = new AckMessage(P2PService.getMyNodeAddress(), AckMessageSourceType.TRADE_MESSAGE, diff --git a/core/src/main/java/haveno/core/trade/messages/DepositRequest.java b/core/src/main/java/haveno/core/trade/messages/DepositRequest.java index 1edb7b6a2e..c743595ed4 100644 --- a/core/src/main/java/haveno/core/trade/messages/DepositRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/DepositRequest.java @@ -62,7 +62,7 @@ public final class DepositRequest extends TradeMessage implements DirectMessage @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.DepositRequest.Builder builder = protobuf.DepositRequest.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid) .setDepositTxHex(depositTxHex) .setDepositTxKey(depositTxKey); diff --git a/core/src/main/java/haveno/core/trade/messages/DepositResponse.java b/core/src/main/java/haveno/core/trade/messages/DepositResponse.java index 6ae2d553a6..c9024a93f3 100644 --- a/core/src/main/java/haveno/core/trade/messages/DepositResponse.java +++ b/core/src/main/java/haveno/core/trade/messages/DepositResponse.java @@ -55,7 +55,7 @@ public final class DepositResponse extends TradeMessage implements DirectMessage @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.DepositResponse.Builder builder = protobuf.DepositResponse.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid); builder.setCurrentDate(currentDate); builder.setBuyerSecurityDeposit(buyerSecurityDeposit); diff --git a/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java b/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java index 5c1fa6aeb0..2d66df218a 100644 --- a/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java @@ -61,7 +61,7 @@ public final class DepositsConfirmedMessage extends TradeMailboxMessage { @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.DepositsConfirmedMessage.Builder builder = protobuf.DepositsConfirmedMessage.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setPubKeyRing(pubKeyRing.toProtoMessage()) .setUid(uid); diff --git a/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java b/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java index f1bbe5354d..f8776e21b7 100644 --- a/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java @@ -59,7 +59,7 @@ public final class InitMultisigRequest extends TradeMessage implements DirectMes @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.InitMultisigRequest.Builder builder = protobuf.InitMultisigRequest.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid); Optional.ofNullable(preparedMultisigHex).ifPresent(e -> builder.setPreparedMultisigHex(preparedMultisigHex)); diff --git a/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java b/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java index d0e173163c..12ce4b7d04 100644 --- a/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java @@ -36,7 +36,6 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag private final NodeAddress senderNodeAddress; private final long tradeAmount; private final long tradePrice; - private final long tradeFee; private final String accountId; private final String paymentAccountId; private final String paymentMethodId; @@ -63,12 +62,11 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag @Nullable private final byte[] makerSignature; - public InitTradeRequest(String tradeId, + public InitTradeRequest(String offerId, NodeAddress senderNodeAddress, PubKeyRing pubKeyRing, long tradeAmount, long tradePrice, - long tradeFee, String accountId, String paymentAccountId, String paymentMethodId, @@ -84,12 +82,11 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag @Nullable String reserveTxKey, @Nullable String payoutAddress, @Nullable byte[] makerSignature) { - super(messageVersion, tradeId, uid); + super(messageVersion, offerId, uid); this.senderNodeAddress = senderNodeAddress; this.pubKeyRing = pubKeyRing; this.tradeAmount = tradeAmount; this.tradePrice = tradePrice; - this.tradeFee = tradeFee; this.accountId = accountId; this.paymentAccountId = paymentAccountId; this.paymentMethodId = paymentMethodId; @@ -113,13 +110,12 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.InitTradeRequest.Builder builder = protobuf.InitTradeRequest.newBuilder() - .setTradeId(tradeId) + .setOfferId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setTakerNodeAddress(takerNodeAddress.toProtoMessage()) .setMakerNodeAddress(makerNodeAddress.toProtoMessage()) .setTradeAmount(tradeAmount) .setTradePrice(tradePrice) - .setTradeFee(tradeFee) .setPubKeyRing(pubKeyRing.toProtoMessage()) .setPaymentAccountId(paymentAccountId) .setPaymentMethodId(paymentMethodId) @@ -141,12 +137,11 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag public static InitTradeRequest fromProto(protobuf.InitTradeRequest proto, CoreProtoResolver coreProtoResolver, String messageVersion) { - return new InitTradeRequest(proto.getTradeId(), + return new InitTradeRequest(proto.getOfferId(), NodeAddress.fromProto(proto.getSenderNodeAddress()), PubKeyRing.fromProto(proto.getPubKeyRing()), proto.getTradeAmount(), proto.getTradePrice(), - proto.getTradeFee(), proto.getAccountId(), proto.getPaymentAccountId(), proto.getPaymentMethodId(), @@ -168,9 +163,9 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag public String toString() { return "InitTradeRequest{" + "\n senderNodeAddress=" + senderNodeAddress + + ",\n offerId=" + offerId + ",\n tradeAmount=" + tradeAmount + ",\n tradePrice=" + tradePrice + - ",\n tradeFee=" + tradeFee + ",\n pubKeyRing=" + pubKeyRing + ",\n accountId='" + accountId + '\'' + ",\n paymentAccountId=" + paymentAccountId + diff --git a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java index 324a4845c6..3f8d48cbec 100644 --- a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java @@ -61,7 +61,7 @@ public final class MediatedPayoutTxPublishedMessage extends TradeMailboxMessage public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { return getNetworkEnvelopeBuilder() .setMediatedPayoutTxPublishedMessage(protobuf.MediatedPayoutTxPublishedMessage.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setPayoutTx(ByteString.copyFrom(payoutTx)) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid)) diff --git a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java index aa7cccb1b7..edc85671cd 100644 --- a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java @@ -63,7 +63,7 @@ public class MediatedPayoutTxSignatureMessage extends TradeMailboxMessage { return getNetworkEnvelopeBuilder() .setMediatedPayoutTxSignatureMessage(protobuf.MediatedPayoutTxSignatureMessage.newBuilder() .setTxSignature(ByteString.copyFrom(txSignature)) - .setTradeId(tradeId) + .setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid)) .build(); @@ -79,8 +79,8 @@ public class MediatedPayoutTxSignatureMessage extends TradeMailboxMessage { } @Override - public String getTradeId() { - return tradeId; + public String getOfferId() { + return offerId; } @@ -88,7 +88,7 @@ public class MediatedPayoutTxSignatureMessage extends TradeMailboxMessage { public String toString() { return "MediatedPayoutSignatureMessage{" + "\n txSignature=" + Utilities.bytesAsHexString(txSignature) + - ",\n tradeId='" + tradeId + '\'' + + ",\n tradeId='" + offerId + '\'' + ",\n senderNodeAddress=" + senderNodeAddress + "\n} " + super.toString(); } diff --git a/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java index b72f74aa38..a7f23190d6 100644 --- a/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java @@ -105,7 +105,7 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage { @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.PaymentReceivedMessage.Builder builder = protobuf.PaymentReceivedMessage.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid) .setDeferPublishPayout(deferPublishPayout); diff --git a/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java b/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java index babebe7f58..6b6f400add 100644 --- a/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java @@ -101,7 +101,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage { @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { final protobuf.PaymentSentMessage.Builder builder = protobuf.PaymentSentMessage.newBuilder(); - builder.setTradeId(tradeId) + builder.setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid); @@ -141,7 +141,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage { @Override public String toString() { return "PaymentSentMessage{" + - ",\n tradeId=" + tradeId + + ",\n tradeId=" + offerId + ",\n uid='" + uid + '\'' + ",\n senderNodeAddress=" + senderNodeAddress + ",\n counterCurrencyTxId=" + counterCurrencyTxId + diff --git a/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java b/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java index cfdb0f6fa8..8945904421 100644 --- a/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java @@ -64,7 +64,7 @@ public final class SignContractRequest extends TradeMessage implements DirectMes @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.SignContractRequest.Builder builder = protobuf.SignContractRequest.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid) .setAccountId(accountId) .setPaymentAccountPayloadHash(ByteString.copyFrom(paymentAccountPayloadHash)) diff --git a/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java b/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java index 29fe50932b..ec85dacd48 100644 --- a/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java +++ b/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java @@ -58,7 +58,7 @@ public final class SignContractResponse extends TradeMessage implements DirectMe @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.SignContractResponse.Builder builder = protobuf.SignContractResponse.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid); Optional.ofNullable(contractAsJson).ifPresent(e -> builder.setContractAsJson(contractAsJson)); diff --git a/core/src/main/java/haveno/core/trade/messages/TradeMessage.java b/core/src/main/java/haveno/core/trade/messages/TradeMessage.java index f4d2eb3cc3..9642f00130 100644 --- a/core/src/main/java/haveno/core/trade/messages/TradeMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/TradeMessage.java @@ -27,12 +27,12 @@ import lombok.ToString; @Getter @ToString public abstract class TradeMessage extends NetworkEnvelope implements UidMessage { - protected final String tradeId; + protected final String offerId; protected final String uid; - protected TradeMessage(String messageVersion, String tradeId, String uid) { + protected TradeMessage(String messageVersion, String offerId, String uid) { super(messageVersion); - this.tradeId = tradeId; + this.offerId = offerId; this.uid = uid; } } diff --git a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java index 6a2d18d74a..3c39fc7513 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java @@ -109,7 +109,7 @@ public class ArbitratorProtocol extends DisputeProtocol { @Override public void handleDepositResponse(DepositResponse response, NodeAddress sender) { - log.warn("Arbitrator ignoring DepositResponse for trade " + response.getTradeId()); + log.warn("Arbitrator ignoring DepositResponse for trade " + response.getOfferId()); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java b/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java index 532d90b7d2..d237006197 100644 --- a/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java @@ -237,7 +237,7 @@ public class FluentProtocol { boolean isTradeIdValid = message == null || isTradeIdValid(trade.getId(), message); if (!isTradeIdValid) { String info = MessageFormat.format("TradeId does not match tradeId in message, TradeId={0}, tradeId in message={1}", - trade.getId(), message.getTradeId()); + trade.getId(), message.getOfferId()); result = Result.INVALID_TRADE_ID.info(info); return result; } diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index 157e10be9d..d9fc5a24dd 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -121,12 +121,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D /////////////////////////////////////////////////////////////////////////////////////////// protected void onTradeMessage(TradeMessage message, NodeAddress peerNodeAddress) { - log.info("Received {} as TradeMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid()); + log.info("Received {} as TradeMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getOfferId(), message.getUid()); ThreadUtils.execute(() -> handle(message, peerNodeAddress), trade.getId()); } protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) { - log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid()); + log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getOfferId(), message.getUid()); ThreadUtils.execute(() -> handle(message, peerNodeAddress), trade.getId()); } @@ -156,7 +156,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D // notify trade listeners // TODO (woodser): better way to register message notifications for trade? - if (((TradeMessage) networkEnvelope).getTradeId().equals(processModel.getOfferId())) { + if (((TradeMessage) networkEnvelope).getOfferId().equals(processModel.getOfferId())) { trade.onVerifiedTradeMessage((TradeMessage) networkEnvelope, peer); } } else if (networkEnvelope instanceof AckMessage) { @@ -862,7 +862,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D private boolean isMyMessage(NetworkEnvelope message) { if (message instanceof TradeMessage) { TradeMessage tradeMessage = (TradeMessage) message; - return tradeMessage.getTradeId().equals(trade.getId()); + return tradeMessage.getOfferId().equals(trade.getId()); } else if (message instanceof AckMessage) { AckMessage ackMessage = (AckMessage) message; return ackMessage.getSourceType() == AckMessageSourceType.TRADE_MESSAGE && ackMessage.getSourceId().equals(trade.getId()); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java index c2a6f5ccf2..fd2d8385c8 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java @@ -89,6 +89,7 @@ public class ArbitratorProcessDepositRequest extends TradeTask { try { txResult = trade.getXmrWalletService().verifyTradeTx( offer.getId(), + null, tradeFee, sendAmount, securityDeposit, diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java index aa2df99097..dec7c5e57a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java @@ -21,6 +21,7 @@ import haveno.common.taskrunner.TaskRunner; import haveno.common.util.Tuple2; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.protocol.TradePeer; @@ -54,13 +55,15 @@ public class ArbitratorProcessReserveTx extends TradeTask { // TODO (woodser): if signer online, should never be called by maker // process reserve tx with expected values - BigInteger tradeFee = isFromMaker ? trade.getMakerFee() : trade.getTakerFee(); + BigInteger penaltyFee = HavenoUtils.multiply(isFromMaker ? offer.getAmount() : trade.getAmount(), offer.getPenaltyFeePct()); + BigInteger tradeFee = isFromMaker ? offer.getMaxMakerFee() : trade.getTakerFee(); BigInteger sendAmount = isFromBuyer ? BigInteger.ZERO : isFromMaker ? offer.getAmount() : trade.getAmount(); // maker reserve tx is for offer amount BigInteger securityDeposit = isFromMaker ? isFromBuyer ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit() : isFromBuyer ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee(); Tuple2 txResult; try { txResult = trade.getXmrWalletService().verifyTradeTx( offer.getId(), + penaltyFee, tradeFee, sendAmount, securityDeposit, diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java index 09339b4113..a836d05501 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java @@ -60,7 +60,6 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { request.getPubKeyRing(), trade.getAmount().longValueExact(), trade.getPrice().getValue(), - trade.getTakerFee().longValueExact(), request.getAccountId(), request.getPaymentAccountId(), request.getPaymentMethodId(), @@ -78,7 +77,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { null); // send request to maker - log.info("Send {} with offerId {} and uid {} to maker {}", makerRequest.getClass().getSimpleName(), makerRequest.getTradeId(), makerRequest.getUid(), trade.getMaker().getNodeAddress()); + log.info("Send {} with offerId {} and uid {} to maker {}", makerRequest.getClass().getSimpleName(), makerRequest.getOfferId(), makerRequest.getUid(), trade.getMaker().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( trade.getMaker().getNodeAddress(), // TODO (woodser): maker's address might be different from original owner address if they disconnect and reconnect, need to validate and update address when requests received trade.getMaker().getPubKeyRing(), @@ -86,7 +85,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived at maker: offerId={}; uid={}", makerRequest.getClass().getSimpleName(), makerRequest.getTradeId(), makerRequest.getUid()); + log.info("{} arrived at maker: offerId={}; uid={}", makerRequest.getClass().getSimpleName(), makerRequest.getOfferId(), makerRequest.getUid()); complete(); } @Override @@ -136,7 +135,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { null); // send request to maker - log.info("Send {} with offerId {} and uid {} to maker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid(), trade.getMaker().getNodeAddress()); + log.info("Send {} with offerId {} and uid {} to maker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid(), trade.getMaker().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( trade.getMaker().getNodeAddress(), trade.getMaker().getPubKeyRing(), @@ -144,7 +143,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived at maker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid()); + log.info("{} arrived at maker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid()); } @Override public void onFault(String errorMessage) { @@ -154,7 +153,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { ); // send request to taker - log.info("Send {} with offerId {} and uid {} to taker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid(), trade.getTaker().getNodeAddress()); + log.info("Send {} with offerId {} and uid {} to taker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid(), trade.getTaker().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( trade.getTaker().getNodeAddress(), trade.getTaker().getPubKeyRing(), @@ -162,7 +161,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived at taker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid()); + log.info("{} arrived at taker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid()); } @Override public void onFault(String errorMessage) { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java index 6ff740cc16..0d31e4e64d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java @@ -57,7 +57,6 @@ public class MakerSendInitTradeRequest extends TradeTask { processModel.getPubKeyRing(), trade.getAmount().longValueExact(), trade.getPrice().getValue(), - offer.getMakerFee().longValueExact(), trade.getProcessModel().getAccountId(), offer.getMakerPaymentAccountId(), offer.getOfferPayload().getPaymentMethodId(), @@ -75,7 +74,7 @@ public class MakerSendInitTradeRequest extends TradeTask { null); // send request to arbitrator - log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getTradeId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); + log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getOfferId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( trade.getArbitrator().getNodeAddress(), trade.getArbitrator().getPubKeyRing(), diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java index c8df4dd9cc..1a37e68cd5 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java @@ -150,7 +150,7 @@ public class ProcessInitMultisigRequest extends TradeTask { sendInitMultisigRequest(peer1Address, peer1PubKeyRing, new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer1Address, request.getTradeId(), request.getUid()); + log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer1Address, request.getOfferId(), request.getUid()); ack1 = true; if (ack1 && ack2) completeAux(); } @@ -166,7 +166,7 @@ public class ProcessInitMultisigRequest extends TradeTask { sendInitMultisigRequest(peer2Address, peer2PubKeyRing, new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer2Address, request.getTradeId(), request.getUid()); + log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer2Address, request.getOfferId(), request.getUid()); ack2 = true; if (ack1 && ack2) completeAux(); } @@ -212,7 +212,7 @@ public class ProcessInitMultisigRequest extends TradeTask { trade.getSelf().getMadeMultisigHex(), trade.getSelf().getExchangedMultisigHex()); - log.info("Send {} with offerId {} and uid {} to peer {}", request.getClass().getSimpleName(), request.getTradeId(), request.getUid(), recipient); + log.info("Send {} with offerId {} and uid {} to peer {}", request.getClass().getSimpleName(), request.getOfferId(), request.getUid(), recipient); processModel.getP2PService().sendEncryptedDirectMessage(recipient, pubKeyRing, request, listener); } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java index b5cff65859..157d797410 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java @@ -69,20 +69,20 @@ public abstract class SendMailboxMessageTask extends TradeTask { new SendMailboxMessageListener() { @Override public void onArrived() { - log.info("{} arrived at peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} arrived at peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); setStateArrived(); if (!task.isCompleted()) complete(); } @Override public void onStoredInMailbox() { - log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); SendMailboxMessageTask.this.onStoredInMailbox(); } @Override public void onFault(String errorMessage) { - log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid(), errorMessage); + log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}", message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid(), errorMessage); SendMailboxMessageTask.this.onFault(errorMessage, message); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java index e43e790fdc..5058af598f 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java @@ -19,6 +19,7 @@ package haveno.core.trade.protocol.tasks; import haveno.common.taskrunner.TaskRunner; import haveno.core.offer.OfferDirection; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.model.XmrAddressEntry; @@ -41,11 +42,12 @@ public class TakerReserveTradeFunds extends TradeTask { runInterceptHook(); // create reserve tx + BigInteger penaltyFee = HavenoUtils.multiply(trade.getAmount(), trade.getOffer().getPenaltyFeePct()); BigInteger takerFee = trade.getTakerFee(); BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getAmount() : BigInteger.ZERO; BigInteger securityDeposit = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getSellerSecurityDepositBeforeMiningFee() : trade.getBuyerSecurityDepositBeforeMiningFee(); String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); - MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(takerFee, sendAmount, securityDeposit, returnAddress, false, null); + MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, takerFee, sendAmount, securityDeposit, returnAddress, false, null); // check if trade still exists if (!processModel.getTradeManager().hasOpenTrade(trade)) { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java index 8fa8ea344b..d1639e5130 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java @@ -117,12 +117,11 @@ public class TakerSendInitTradeRequestToArbitrator extends TradeTask { // create request to arbitrator InitTradeRequest makerRequest = (InitTradeRequest) processModel.getTradeMessage(); // taker's InitTradeRequest to maker InitTradeRequest arbitratorRequest = new InitTradeRequest( - makerRequest.getTradeId(), + makerRequest.getOfferId(), makerRequest.getSenderNodeAddress(), makerRequest.getPubKeyRing(), makerRequest.getTradeAmount(), makerRequest.getTradePrice(), - makerRequest.getTradeFee(), makerRequest.getAccountId(), makerRequest.getPaymentAccountId(), makerRequest.getPaymentMethodId(), @@ -140,7 +139,7 @@ public class TakerSendInitTradeRequestToArbitrator extends TradeTask { processModel.getMakerSignature()); // send request to arbitrator - log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getTradeId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); + log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getOfferId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( arbitratorNodeAddress, arbitrator.getPubKeyRing(), diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java index ec7155482e..a11a3e8984 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java @@ -53,8 +53,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { trade.getId(), p2PService.getAddress(), UUID.randomUUID().toString()); - log.info("Send {} to peer {}. tradeId={}, uid={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("Send {} to peer {}. offerId={}, uid={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); trade.setMediationResultState(MediationResultState.SIG_MSG_SENT); processModel.getTradeManager().requestPersistence(); @@ -64,8 +64,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { new SendMailboxMessageListener() { @Override public void onArrived() { - log.info("{} arrived at peer {}. tradeId={}, uid={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} arrived at peer {}. offerId={}, uid={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); trade.setMediationResultState(MediationResultState.SIG_MSG_ARRIVED); processModel.getTradeManager().requestPersistence(); @@ -74,8 +74,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { @Override public void onStoredInMailbox() { - log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} stored in mailbox for peer {}. offerId={}, uid={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); trade.setMediationResultState(MediationResultState.SIG_MSG_IN_MAILBOX); processModel.getTradeManager().requestPersistence(); @@ -84,8 +84,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { @Override public void onFault(String errorMessage) { - log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid(), errorMessage); + log.error("{} failed: Peer {}. offerId={}, uid={}, errorMessage={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid(), errorMessage); trade.setMediationResultState(MediationResultState.SIG_MSG_SEND_FAILED); appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage); processModel.getTradeManager().requestPersistence(); diff --git a/core/src/main/java/haveno/core/util/Validator.java b/core/src/main/java/haveno/core/util/Validator.java index 2b2ea41632..fa2807ab31 100644 --- a/core/src/main/java/haveno/core/util/Validator.java +++ b/core/src/main/java/haveno/core/util/Validator.java @@ -56,6 +56,6 @@ public class Validator { } public static boolean isTradeIdValid(String tradeId, TradeMessage tradeMessage) { - return tradeId.equals(tradeMessage.getTradeId()); + return tradeId.equals(tradeMessage.getOfferId()); } } diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java index 73220c608e..7ded1e7dfc 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -532,20 +532,21 @@ public class XmrWalletService { /** * Create the reserve tx and freeze its inputs. The full amount is returned - * to the sender's payout address less the security deposit and mining fee. + * to the sender's payout address less the penalty and mining fees. * + * @param penaltyFee penalty fee for breaking protocol * @param tradeFee trade fee - * @param sendAmount amount to give peer + * @param sendAmount amount to send peer * @param securityDeposit security deposit amount * @param returnAddress return address for reserved funds * @param reserveExactAmount specifies to reserve the exact input amount * @param preferredSubaddressIndex preferred source subaddress to spend from (optional) * @return a transaction to reserve a trade */ - public MoneroTxWallet createReserveTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String returnAddress, boolean reserveExactAmount, Integer preferredSubaddressIndex) { + public MoneroTxWallet createReserveTx(BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String returnAddress, boolean reserveExactAmount, Integer preferredSubaddressIndex) { log.info("Creating reserve tx with preferred subaddress index={}, return address={}", preferredSubaddressIndex, returnAddress); long time = System.currentTimeMillis(); - MoneroTxWallet reserveTx = createTradeTx(tradeFee, sendAmount, securityDeposit, returnAddress, reserveExactAmount, preferredSubaddressIndex); + MoneroTxWallet reserveTx = createTradeTx(penaltyFee, tradeFee, sendAmount, securityDeposit, returnAddress, reserveExactAmount, preferredSubaddressIndex); log.info("Done creating reserve tx in {} ms", System.currentTimeMillis() - time); return reserveTx; } @@ -568,18 +569,18 @@ public class XmrWalletService { // create deposit tx String multisigAddress = trade.getProcessModel().getMultisigAddress(); - BigInteger tradeFee = trade instanceof MakerTrade ? trade.getOffer().getMakerFee() : trade.getTakerFee(); + BigInteger tradeFee = trade instanceof MakerTrade ? trade.getMakerFee() : trade.getTakerFee(); BigInteger sendAmount = trade instanceof BuyerTrade ? BigInteger.ZERO : trade.getAmount(); BigInteger securityDeposit = trade instanceof BuyerTrade ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee(); long time = System.currentTimeMillis(); log.info("Creating deposit tx with multisig address={}", multisigAddress); - MoneroTxWallet depositTx = createTradeTx(tradeFee, sendAmount, securityDeposit, multisigAddress, reserveExactAmount, preferredSubaddressIndex); + MoneroTxWallet depositTx = createTradeTx(null, tradeFee, sendAmount, securityDeposit, multisigAddress, reserveExactAmount, preferredSubaddressIndex); log.info("Done creating deposit tx for trade {} {} in {} ms", trade.getClass().getSimpleName(), trade.getId(), System.currentTimeMillis() - time); return depositTx; } } - private MoneroTxWallet createTradeTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, boolean reserveExactAmount, Integer preferredSubaddressIndex) { + private MoneroTxWallet createTradeTx(BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, boolean reserveExactAmount, Integer preferredSubaddressIndex) { synchronized (walletLock) { MoneroWallet wallet = getWallet(); @@ -604,27 +605,31 @@ public class XmrWalletService { // first try preferred subaddressess for (int i = 0; i < subaddressIndices.size(); i++) { try { - return createTradeTxFromSubaddress(tradeFee, sendAmount, securityDeposit, address, reserveExactAmount, subaddressIndices.get(i)); + return createTradeTxFromSubaddress(penaltyFee, tradeFee, sendAmount, securityDeposit, address, reserveExactAmount, subaddressIndices.get(i)); } catch (Exception e) { if (i == subaddressIndices.size() - 1 && reserveExactAmount) throw e; // throw if no subaddress with exact output } } // try any subaddress - return createTradeTxFromSubaddress(tradeFee, sendAmount, securityDeposit, address, reserveExactAmount, null); + return createTradeTxFromSubaddress(penaltyFee, tradeFee, sendAmount, securityDeposit, address, reserveExactAmount, null); } } - private MoneroTxWallet createTradeTxFromSubaddress(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, boolean reserveExactAmount, Integer subaddressIndex) { + private MoneroTxWallet createTradeTxFromSubaddress(BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, boolean reserveExactAmount, Integer subaddressIndex) { // create tx - MoneroTxWallet tradeTx = wallet.createTx(new MoneroTxConfig() + boolean isDepositTx = penaltyFee == null; + BigInteger feeAmount = isDepositTx ? tradeFee : penaltyFee; + BigInteger transferAmount = isDepositTx ? sendAmount.add(securityDeposit) : sendAmount.add(securityDeposit).add(tradeFee).subtract(penaltyFee); + MoneroTxConfig txConfig = new MoneroTxConfig() .setAccountIndex(0) .setSubaddressIndices(subaddressIndex) - .addDestination(HavenoUtils.getTradeFeeAddress(), tradeFee) - .addDestination(address, sendAmount.add(securityDeposit)) - .setSubtractFeeFrom(1) - .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY)); // pay fee from security deposit + .addDestination(address, transferAmount) + .setSubtractFeeFrom(0) // pay fee from transfer amount + .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY); + if (!BigInteger.valueOf(0).equals(feeAmount)) txConfig.addDestination(HavenoUtils.getTradeFeeAddress(), feeAmount); + MoneroTxWallet tradeTx = wallet.createTx(txConfig); // freeze inputs List keyImages = new ArrayList(); @@ -639,6 +644,7 @@ public class XmrWalletService { * The transaction is submitted to the pool then flushed without relaying. * * @param offerId id of offer to verify trade tx + * @param penaltyFee penalty fee for breaking protocol * @param tradeFee trade fee * @param sendAmount amount to give peer * @param securityDeposit security deposit amount @@ -647,9 +653,9 @@ public class XmrWalletService { * @param txHex transaction hex * @param txKey transaction key * @param keyImages expected key images of inputs, ignored if null - * @return tuple with the verified tx and its actual security deposit + * @return tuple with the verified tx and the actual security deposit */ - public Tuple2 verifyTradeTx(String offerId, BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, String txHash, String txHex, String txKey, List keyImages) { + public Tuple2 verifyTradeTx(String offerId, BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, String txHash, String txHex, String txKey, List keyImages) { if (txHash == null) throw new IllegalArgumentException("Cannot verify trade tx with null id"); MoneroDaemonRpc daemon = getDaemon(); MoneroWallet wallet = getWallet(); @@ -681,39 +687,45 @@ public class XmrWalletService { if (!BigInteger.ZERO.equals(tx.getUnlockTime())) throw new RuntimeException("Unlock height must be 0"); // verify miner fee - BigInteger feeEstimate = getElevatedFeeEstimate(tx.getWeight()); - double feeDiff = tx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); - if (feeDiff > MINER_FEE_TOLERANCE) throw new Error("Miner fee is not within " + (MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + tx.getFee()); - log.info("Trade tx fee {} is within tolerance, diff%={}", tx.getFee(), feeDiff); + BigInteger minerFeeEstimate = getElevatedFeeEstimate(tx.getWeight()); + double minerFeeDiff = tx.getFee().subtract(minerFeeEstimate).abs().doubleValue() / minerFeeEstimate.doubleValue(); + if (minerFeeDiff > MINER_FEE_TOLERANCE) throw new Error("Miner fee is not within " + (MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + minerFeeEstimate + " but was " + tx.getFee()); + log.info("Trade tx fee {} is within tolerance, diff%={}", tx.getFee(), minerFeeDiff); - // verify transfer proof to fee address - MoneroCheckTx tradeFeeCheck = wallet.checkTxKey(txHash, txKey, HavenoUtils.getTradeFeeAddress()); - if (!tradeFeeCheck.isGood()) throw new RuntimeException("Invalid proof to trade fee address"); + // verify proof to fee address + MoneroCheckTx feeCheck = wallet.checkTxKey(txHash, txKey, HavenoUtils.getTradeFeeAddress()); + if (!feeCheck.isGood()) throw new RuntimeException("Invalid proof to trade fee address"); - // verify transfer proof to address + // verify proof to transfer address MoneroCheckTx transferCheck = wallet.checkTxKey(txHash, txKey, address); if (!transferCheck.isGood()) throw new RuntimeException("Invalid proof to transfer address"); - // collect actual trade fee, send amount, and security deposit - BigInteger actualTradeFee = tradeFeeCheck.getReceivedAmount(); - actualSecurityDeposit = transferCheck.getReceivedAmount().subtract(sendAmount); - BigInteger actualSendAmount = transferCheck.getReceivedAmount().subtract(actualSecurityDeposit); + // verify fee and transfer amounts + BigInteger actualFee = feeCheck.getReceivedAmount(); + BigInteger actualTransferAmount = transferCheck.getReceivedAmount(); + boolean isDepositTx = penaltyFee == null; + if (isDepositTx) { - // verify trade fee - if (actualTradeFee.compareTo(tradeFee) < 0) { - throw new RuntimeException("Insufficient trade fee, expected=" + tradeFee + ", actual=" + actualTradeFee + ", transfer address check=" + JsonUtils.serialize(transferCheck) + ", trade fee address check=" + JsonUtils.serialize(tradeFeeCheck)); + // verify trade fee + if (!actualFee.equals(tradeFee)) throw new RuntimeException("Invalid trade fee amount, expected " + tradeFee + " but was " + actualFee); + + // verify multisig deposit amount + BigInteger expectedTransferAmount = sendAmount.add(securityDeposit).subtract(tx.getFee()); + if (!actualTransferAmount.equals(expectedTransferAmount)) throw new RuntimeException("Invalid multisig deposit amount, expected " + expectedTransferAmount + " but was " + actualTransferAmount); + actualSecurityDeposit = actualTransferAmount.subtract(sendAmount); + } else { + + // verify penalty fee + if (!actualFee.equals(penaltyFee)) throw new RuntimeException("Invalid penalty fee amount, expected " + penaltyFee + " but was " + actualFee); + + // verify return amount + BigInteger expectedTransferAmount = sendAmount.add(securityDeposit).add(tradeFee).subtract(penaltyFee).subtract(tx.getFee()); + if (!actualTransferAmount.equals(expectedTransferAmount)) throw new RuntimeException("Invalid return amount, expected " + expectedTransferAmount + " but was " + actualTransferAmount); + actualSecurityDeposit = actualTransferAmount.subtract(sendAmount).subtract(tradeFee); } - // verify send amount - if (!actualSendAmount.equals(sendAmount)) { - throw new RuntimeException("Unexpected send amount, expected " + sendAmount + " but was " + actualSendAmount); - } - - // verify security deposit - BigInteger expectedSecurityDeposit = securityDeposit.subtract(tx.getFee()); // fee is paid from security deposit - if (!actualSecurityDeposit.equals(expectedSecurityDeposit)) { - throw new RuntimeException("Unexpected security deposit amount, expected " + expectedSecurityDeposit + " but was " + actualSecurityDeposit); - } + // return the result + return new Tuple2<>(tx, actualSecurityDeposit); } catch (Exception e) { log.warn("Error verifying trade tx with offer id=" + offerId + (tx == null ? "" : ", tx=" + tx) + ": " + e.getMessage()); throw e; @@ -725,7 +737,6 @@ public class XmrWalletService { throw err.getCode().equals(-32601) ? new RuntimeException("Failed to flush tx from pool. Arbitrator must use trusted, unrestricted daemon") : err; } } - return new Tuple2<>(tx, actualSecurityDeposit); } } diff --git a/core/src/test/java/haveno/core/offer/OfferMaker.java b/core/src/test/java/haveno/core/offer/OfferMaker.java index 0d01d4ef3e..52084f209b 100644 --- a/core/src/test/java/haveno/core/offer/OfferMaker.java +++ b/core/src/test/java/haveno/core/offer/OfferMaker.java @@ -46,6 +46,11 @@ public class OfferMaker { lookup.valueOf(useMarketBasedPrice, false), lookup.valueOf(amount, 100000L), lookup.valueOf(minAmount, 100000L), + 0L, + 0L, + 0L, + 0L, + 0L, lookup.valueOf(baseCurrencyCode, "XMR"), lookup.valueOf(counterCurrencyCode, "USD"), "SEPA", @@ -58,9 +63,6 @@ public class OfferMaker { 0L, 0L, 0L, - 0L, - 0L, - 0L, false, false, 0L, diff --git a/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java b/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java index 7005485542..eb8e2e124d 100644 --- a/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java +++ b/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java @@ -31,11 +31,26 @@ import static org.junit.jupiter.api.Assertions.fail; public class CoinUtilTest { @Test - public void testGetFeePerBtc() { - assertEquals(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.xmrToAtomicUnits(1))); - assertEquals(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(1))); - assertEquals(HavenoUtils.xmrToAtomicUnits(0.01), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1))); - assertEquals(HavenoUtils.xmrToAtomicUnits(0.015), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.3), HavenoUtils.xmrToAtomicUnits(0.05))); + public void testGetPercentOfAmount() { + BigInteger bi = new BigInteger("703100000000"); + assertEquals(new BigInteger("105465000000"), HavenoUtils.multiply(bi, .15)); + } + + @Test + public void testGetFeePerXmr() { + assertEquals(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(1), 1.0)); + assertEquals(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(0.1), 1.0)); + assertEquals(HavenoUtils.xmrToAtomicUnits(0.01), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(0.1), 0.1)); + assertEquals(HavenoUtils.xmrToAtomicUnits(0.015), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(0.3), 0.05)); + } + + @Test + public void testParseXmr() { + String xmrStr = "0.266394780889"; + BigInteger au = HavenoUtils.parseXmr(xmrStr); + assertEquals(new BigInteger("266394780889"), au); + assertEquals(xmrStr, "" + HavenoUtils.atomicUnitsToXmr(au)); + assertEquals(xmrStr, HavenoUtils.formatXmr(au, false)); } @Test diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java index 3d8f00f1b8..f94ccbd3f7 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java @@ -545,7 +545,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { // Maker does not pay the mining fee for the trade txs because the mining fee might be different when maker // created the offer and reserved his funds, so that would not work well with dynamic fees. // The mining fee for the createOfferFee tx is deducted from the createOfferFee and not visible to the trader - final BigInteger makerFee = getMakerFee(); + final BigInteger makerFee = getMaxMakerFee(); if (direction != null && amount.get() != null && makerFee != null) { BigInteger feeAndSecDeposit = getSecurityDeposit().add(makerFee); BigInteger total = isBuyOffer() ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get()); @@ -677,8 +677,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel { this.marketPriceAvailable = marketPriceAvailable; } - public BigInteger getMakerFee() { - return HavenoUtils.getMakerFee(amount.get()); + public BigInteger getMaxMakerFee() { + return HavenoUtils.multiply(amount.get(), HavenoUtils.MAKER_FEE_PCT); } boolean canPlaceOffer() { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java index e221341078..f30a930c67 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java @@ -491,7 +491,7 @@ public abstract class MutableOfferViewModel ext tradeFeeCurrencyCode.set(Res.getBaseCurrencyCode()); tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionXMROnly")); - BigInteger makerFee = dataModel.getMakerFee(); + BigInteger makerFee = dataModel.getMaxMakerFee(); if (makerFee == null) { return; } @@ -499,7 +499,7 @@ public abstract class MutableOfferViewModel ext isTradeFeeVisible.setValue(true); tradeFee.set(HavenoUtils.formatXmr(makerFee)); tradeFeeInXmrWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, - dataModel.getMakerFee(), + dataModel.getMaxMakerFee(), btcFormatter)); } @@ -1004,8 +1004,7 @@ public abstract class MutableOfferViewModel ext return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, dataModel.getSecurityDeposit(), dataModel.getAmount().get(), - btcFormatter, - Restrictions.getMinBuyerSecurityDeposit() + btcFormatter ); } @@ -1016,14 +1015,13 @@ public abstract class MutableOfferViewModel ext public String getTradeFee() { return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, - dataModel.getMakerFee(), + dataModel.getMaxMakerFee(), dataModel.getAmount().get(), - btcFormatter, - HavenoUtils.getMinMakerFee()); + btcFormatter); } public String getMakerFeePercentage() { - final BigInteger makerFee = dataModel.getMakerFee(); + final BigInteger makerFee = dataModel.getMaxMakerFee(); return GUIUtil.getPercentage(makerFee, dataModel.getAmount().get()); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java index 7d59896b9e..cab7008d74 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java @@ -44,18 +44,10 @@ public class OfferViewModelUtil { public static String getTradeFeeWithFiatEquivalentAndPercentage(OfferUtil offerUtil, BigInteger tradeFee, BigInteger tradeAmount, - CoinFormatter formatter, - BigInteger minTradeFee) { + CoinFormatter formatter) { String feeAsXmr = HavenoUtils.formatXmr(tradeFee, true); String percentage; - if (tradeFee.compareTo(minTradeFee) <= 0) { - percentage = Res.get("guiUtil.requiredMinimum") - .replace("(", "") - .replace(")", ""); - } else { - percentage = GUIUtil.getPercentage(tradeFee, tradeAmount) + - " " + Res.get("guiUtil.ofTradeAmount"); - } + percentage = GUIUtil.getPercentage(tradeFee, tradeAmount) + " " + Res.get("guiUtil.ofTradeAmount"); return offerUtil.getFeeInUserFiatCurrency(tradeFee, formatter) .map(VolumeUtil::formatAverageVolumeWithCode) diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java index 2170881203..234460120d 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -618,10 +618,6 @@ abstract class OfferBookViewModel extends ActivatableViewModel { return true; } - public String getMakerFeeAsString(Offer offer) { - return HavenoUtils.formatXmr(offer.getMakerFee(), true); - } - private static String getDirectionWithCodeDetailed(OfferDirection direction, String currencyCode) { if (CurrencyUtil.isTraditionalCurrency(currencyCode)) return (direction == OfferDirection.BUY) ? Res.get("shared.buyingXMRWith", currencyCode) : Res.get("shared.sellingXMRFor", currencyCode); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java index a80dc05301..3ae9bd4ef7 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -248,7 +248,6 @@ class TakeOfferDataModel extends OfferDataModel { errorMsg = Res.get("offerbook.warning.offerWasAlreadyUsedInTrade"); } else { tradeManager.onTakeOffer(amount.get(), - getTakerFee(), fundsNeededForTrade, offer, paymentAccount.getId(), @@ -404,7 +403,7 @@ class TakeOfferDataModel extends OfferDataModel { @Nullable BigInteger getTakerFee() { - return HavenoUtils.getTakerFee(this.amount.get()); + return HavenoUtils.multiply(this.amount.get(), offer.getTakerFeePct()); } public void swapTradeToSavings() { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java index 04ad8fc07f..9382ca9d77 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -38,7 +38,6 @@ import haveno.core.util.VolumeUtil; import haveno.core.util.coin.CoinFormatter; import haveno.core.util.coin.CoinUtil; import haveno.core.util.validation.InputValidator; -import haveno.core.xmr.wallet.Restrictions; import haveno.desktop.Navigation; import haveno.desktop.common.model.ActivatableWithDataModel; import haveno.desktop.common.model.ViewModel; @@ -656,9 +655,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel im return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, dataModel.getSecurityDeposit(), dataModel.getAmount().get(), - xmrFormatter, - Restrictions.getMinBuyerSecurityDeposit() - ); + xmrFormatter); } public String getSecurityDepositWithCode() { @@ -669,8 +666,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel im return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, dataModel.getTakerFee(), dataModel.getAmount().get(), - xmrFormatter, - HavenoUtils.getMinMakerFee()); + xmrFormatter); } public String getTakerFeePercentage() { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java index 64e68ce9f2..be2b811f07 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java @@ -189,6 +189,11 @@ class EditOfferDataModel extends MutableOfferDataModel { newOfferPayload.isUseMarketBasedPrice(), offerPayload.getAmount(), offerPayload.getMinAmount(), + offerPayload.getMakerFeePct(), + offerPayload.getTakerFeePct(), + offerPayload.getPenaltyFeePct(), + offerPayload.getBuyerSecurityDepositPct(), + offerPayload.getSellerSecurityDepositPct(), newOfferPayload.getBaseCurrencyCode(), newOfferPayload.getCounterCurrencyCode(), newOfferPayload.getPaymentMethodId(), @@ -199,9 +204,6 @@ class EditOfferDataModel extends MutableOfferDataModel { newOfferPayload.getAcceptedBankIds(), offerPayload.getVersionNr(), offerPayload.getBlockHeightAtOfferCreation(), - offerPayload.getMakerFee(), - offerPayload.getBuyerSecurityDepositPct(), - offerPayload.getSellerSecurityDepositPct(), offerPayload.getMaxTradeLimit(), offerPayload.getMaxTradePeriod(), offerPayload.isUseAutoClose(), diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java index 3c5eaf325a..0fe030bc12 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java @@ -27,7 +27,6 @@ import haveno.core.locale.Res; import haveno.core.monetary.Price; import haveno.core.offer.Offer; import haveno.core.offer.OpenOffer; -import haveno.core.trade.HavenoUtils; import haveno.core.util.FormattingUtils; import haveno.core.util.PriceUtil; import haveno.core.util.VolumeUtil; @@ -155,11 +154,6 @@ class OpenOffersViewModel extends ActivatableWithDataModel return GUIUtil.isBootstrappedOrShowPopup(p2PService); } - public String getMakerFeeAsString(OpenOffer openOffer) { - Offer offer = openOffer.getOffer(); - return HavenoUtils.formatXmr(offer.getMakerFee(), true); - } - String getTriggerPrice(OpenOfferListItem item) { if ((item == null)) { return ""; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java index 62cf805ee0..00b98d92b6 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -271,7 +271,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { Offer offer = trade.getOffer(); if (isMaker()) { if (offer != null) { - return offer.getMakerFee(); + return trade.getMakerFee(); } else { log.error("offer is null"); return BigInteger.ZERO; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java index d6bc9b8024..54a9f359a2 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -38,7 +38,6 @@ import haveno.core.util.FormattingUtils; import haveno.core.util.VolumeUtil; import haveno.core.util.coin.CoinFormatter; import haveno.core.util.validation.BtcAddressValidator; -import haveno.core.xmr.wallet.Restrictions; import haveno.desktop.Navigation; import haveno.desktop.common.model.ActivatableWithDataModel; import haveno.desktop.common.model.ViewModel; @@ -272,12 +271,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel pubKeyRing = newProperty(); public static final Property blockHeight = newProperty(); public static final Property txFee = newProperty(); - public static final Property makerFee = newProperty(); - public static final Property buyerSecurityDeposit = newProperty(); - public static final Property sellerSecurityDeposit = newProperty(); + public static final Property makerFeePct = newProperty(); + public static final Property takerFeePct = newProperty(); + public static final Property penaltyFeePct = newProperty(); + public static final Property buyerSecurityDepositPct = newProperty(); + public static final Property sellerSecurityDepositPct = newProperty(); public static final Property tradeLimit = newProperty(); public static final Property maxTradePeriod = newProperty(); public static final Property lowerClosePrice = newProperty(); @@ -80,6 +82,11 @@ public class OfferMaker { lookup.valueOf(useMarketBasedPrice, false), lookup.valueOf(amount, 100000L), lookup.valueOf(minAmount, 100000L), + lookup.valueOf(makerFeePct, .0015), + lookup.valueOf(takerFeePct, .0075), + lookup.valueOf(penaltyFeePct, 0.03), + lookup.valueOf(buyerSecurityDepositPct, .15), + lookup.valueOf(sellerSecurityDepositPct, .15), lookup.valueOf(baseCurrencyCode, "XMR"), lookup.valueOf(counterCurrencyCode, "USD"), lookup.valueOf(paymentMethodId, "SEPA"), @@ -92,9 +99,6 @@ public class OfferMaker { null, "2", lookup.valueOf(blockHeight, 700000L), - lookup.valueOf(makerFee, 1000L), - lookup.valueOf(buyerSecurityDeposit, 10000L), - lookup.valueOf(sellerSecurityDeposit, 10000L), lookup.valueOf(tradeLimit, 0L), lookup.valueOf(maxTradePeriod, 0L), false, diff --git a/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java b/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java index ae3559b462..dc7d68c873 100644 --- a/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java +++ b/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java @@ -103,30 +103,19 @@ public class GUIUtilTest { } @Test - public void percentageOfTradeAmount_higherFeeAsMin() { + public void percentageOfTradeAmount1() { BigInteger fee = BigInteger.valueOf(200000000L); - BigInteger min = BigInteger.valueOf(100000000L); - assertEquals(" (0.02% of trade amount)", GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0), min)); + assertEquals(" (0.02% of trade amount)", GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0))); } @Test - public void percentageOfTradeAmount_minFee() { - - BigInteger fee = BigInteger.valueOf(100000000L); - BigInteger min = BigInteger.valueOf(100000000L); - - assertEquals(" (required minimum)", - GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0), min)); - } - - @Test - public void percentageOfTradeAmount_minFeeZERO() { + public void percentageOfTradeAmount2() { BigInteger fee = BigInteger.valueOf(100000000L); assertEquals(" (0.01% of trade amount)", - GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0), BigInteger.ZERO)); + GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0))); } } diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index cf9a051f3e..86dd3a461a 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -538,28 +538,30 @@ message OfferInfo { double market_price_margin_pct = 5; uint64 amount = 6 [jstype = JS_STRING]; uint64 min_amount = 7 [jstype = JS_STRING]; - string volume = 8; - string min_volume = 9; - double buyer_security_deposit_pct = 10; - double seller_security_deposit_pct = 11; - string trigger_price = 12; - string payment_account_id = 13; - string payment_method_id = 14; - string payment_method_short_name = 15; - string base_currency_code = 16; - string counter_currency_code = 17; - uint64 date = 18; - string state = 19; - uint64 maker_fee = 20 [jstype = JS_STRING]; - bool is_activated = 21; - bool is_my_offer = 22; - string owner_node_address = 23; - string pub_key_ring = 24; - string version_nr = 25; - int32 protocol_version = 26; - string arbitrator_signer = 27; - string split_output_tx_hash = 28; - uint64 split_output_tx_fee = 29 [jstype = JS_STRING]; + double maker_fee_pct = 8; + double taker_fee_pct = 9; + double penalty_fee_pct = 10; + double buyer_security_deposit_pct = 11; + double seller_security_deposit_pct = 12; + string volume = 13; + string min_volume = 14; + string trigger_price = 15; + string payment_account_id = 16; + string payment_method_id = 17; + string payment_method_short_name = 18; + string base_currency_code = 19; + string counter_currency_code = 20; + uint64 date = 21; + string state = 22; + bool is_activated = 23; + bool is_my_offer = 24; + string owner_node_address = 25; + string pub_key_ring = 26; + string version_nr = 27; + int32 protocol_version = 28; + string arbitrator_signer = 29; + string split_output_tx_hash = 30; + uint64 split_output_tx_fee = 31 [jstype = JS_STRING]; } message AvailabilityResultWithDescription { @@ -847,39 +849,40 @@ message TradeInfo { string short_id = 3; uint64 date = 4; string role = 5; - uint64 taker_fee = 6 [jstype = JS_STRING]; - uint64 amount = 7 [jstype = JS_STRING]; - uint64 buyer_security_deposit = 8 [jstype = JS_STRING]; - uint64 seller_security_deposit = 9 [jstype = JS_STRING]; - uint64 buyer_deposit_tx_fee = 10 [jstype = JS_STRING]; - uint64 seller_deposit_tx_fee = 11 [jstype = JS_STRING]; - uint64 buyer_payout_tx_fee = 12 [jstype = JS_STRING]; - uint64 seller_payout_tx_fee = 13 [jstype = JS_STRING]; - uint64 buyer_payout_amount = 14 [jstype = JS_STRING]; - uint64 seller_payout_amount = 15 [jstype = JS_STRING]; - string price = 16; - string arbitrator_node_address = 17; - string trade_peer_node_address = 18; - string state = 19; - string phase = 20; - string period_state = 21; - string payout_state = 22; - string dispute_state = 23; - bool is_deposits_published = 24; - bool is_deposits_confirmed = 25; - bool is_deposits_unlocked = 26; - bool is_payment_sent = 27; - bool is_payment_received = 28; - bool is_payout_published = 29; - bool is_payout_confirmed = 30; - bool is_payout_unlocked = 31; - bool is_completed = 32; - string contract_as_json = 33; - ContractInfo contract = 34; - string trade_volume = 35; - string maker_deposit_tx_id = 36; - string taker_deposit_tx_id = 37; - string payout_tx_id = 38; + uint64 amount = 6 [jstype = JS_STRING]; + uint64 maker_fee = 7 [jstype = JS_STRING]; + uint64 taker_fee = 8 [jstype = JS_STRING]; + uint64 buyer_security_deposit = 9 [jstype = JS_STRING]; + uint64 seller_security_deposit = 10 [jstype = JS_STRING]; + uint64 buyer_deposit_tx_fee = 11 [jstype = JS_STRING]; + uint64 seller_deposit_tx_fee = 12 [jstype = JS_STRING]; + uint64 buyer_payout_tx_fee = 13 [jstype = JS_STRING]; + uint64 seller_payout_tx_fee = 14 [jstype = JS_STRING]; + uint64 buyer_payout_amount = 15 [jstype = JS_STRING]; + uint64 seller_payout_amount = 16 [jstype = JS_STRING]; + string price = 17; + string arbitrator_node_address = 18; + string trade_peer_node_address = 19; + string state = 20; + string phase = 21; + string period_state = 22; + string payout_state = 23; + string dispute_state = 24; + bool is_deposits_published = 25; + bool is_deposits_confirmed = 26; + bool is_deposits_unlocked = 27; + bool is_payment_sent = 28; + bool is_payment_received = 29; + bool is_payout_published = 30; + bool is_payout_confirmed = 31; + bool is_payout_unlocked = 32; + bool is_completed = 33; + string contract_as_json = 34; + ContractInfo contract = 35; + string trade_volume = 36; + string maker_deposit_tx_id = 37; + string taker_deposit_tx_id = 38; + string payout_tx_id = 39; } message ContractInfo { diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index daf9c26934..7ed1081e00 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -226,26 +226,25 @@ message PrefixedSealedAndSignedMessage { } message InitTradeRequest { - string trade_id = 1; + string offer_id = 1; NodeAddress sender_node_address = 2; PubKeyRing pub_key_ring = 3; int64 trade_amount = 4; int64 trade_price = 5; - int64 trade_fee = 6; - string account_id = 7; - string payment_account_id = 8; - string payment_method_id = 9; - string uid = 10; - bytes account_age_witness_signature_of_offer_id = 11; - int64 current_date = 12; - NodeAddress maker_node_address = 13; - NodeAddress taker_node_address = 14; - NodeAddress arbitrator_node_address = 15; - string reserve_tx_hash = 16; - string reserve_tx_hex = 17; - string reserve_tx_key = 18; - string payout_address = 19; - bytes maker_signature = 20; + string account_id = 6; + string payment_account_id = 7; + string payment_method_id = 8; + string uid = 9; + bytes account_age_witness_signature_of_offer_id = 10; + int64 current_date = 11; + NodeAddress maker_node_address = 12; + NodeAddress taker_node_address = 13; + NodeAddress arbitrator_node_address = 14; + string reserve_tx_hash = 15; + string reserve_tx_hex = 16; + string reserve_tx_key = 17; + string payout_address = 18; + bytes maker_signature = 19; } message InitMultisigRequest { @@ -623,29 +622,31 @@ message OfferPayload { bool use_market_based_price = 8; int64 amount = 9; int64 min_amount = 10; - string base_currency_code = 11; - string counter_currency_code = 12; - string payment_method_id = 13; - string maker_payment_account_id = 14; - string country_code = 15; - repeated string accepted_country_codes = 16; - string bank_id = 17; - repeated string accepted_bank_ids = 18; - string version_nr = 19; - int64 block_height_at_offer_creation = 20; - int64 maker_fee = 21; - double buyer_security_deposit_pct = 22; - double seller_security_deposit_pct = 23; - int64 max_trade_limit = 24; - int64 max_trade_period = 25; - bool use_auto_close = 26; - bool use_re_open_after_auto_close = 27; - int64 lower_close_price = 28; - int64 upper_close_price = 29; - bool is_private_offer = 30; - string hash_of_challenge = 31; - map extra_data = 32; - int32 protocol_version = 33; + double maker_fee_pct = 11; + double taker_fee_pct = 12; + double penalty_fee_pct = 13; + double buyer_security_deposit_pct = 14; + double seller_security_deposit_pct = 15; + string base_currency_code = 16; + string counter_currency_code = 17; + string payment_method_id = 18; + string maker_payment_account_id = 19; + string country_code = 20; + repeated string accepted_country_codes = 21; + string bank_id = 22; + repeated string accepted_bank_ids = 23; + string version_nr = 24; + int64 block_height_at_offer_creation = 25; + int64 max_trade_limit = 26; + int64 max_trade_period = 27; + bool use_auto_close = 28; + bool use_re_open_after_auto_close = 29; + int64 lower_close_price = 30; + int64 upper_close_price = 31; + bool is_private_offer = 32; + string hash_of_challenge = 33; + map extra_data = 34; + int32 protocol_version = 35; NodeAddress arbitrator_signer = 1001; bytes arbitrator_signature = 1002; @@ -1496,29 +1497,28 @@ message Trade { string payout_tx_hex = 4; string payout_tx_key = 5; int64 amount = 6; - int64 taker_fee = 8; - int64 take_offer_date = 9; - int64 price = 10; - State state = 11; - PayoutState payout_state = 12; - DisputeState dispute_state = 13; - TradePeriodState period_state = 14; - Contract contract = 15; - string contract_as_json = 16; - bytes contract_hash = 17; - NodeAddress arbitrator_node_address = 18; - NodeAddress mediator_node_address = 19; - string error_message = 20; - string counter_currency_tx_id = 21; - repeated ChatMessage chat_message = 22; - MediationResultState mediation_result_state = 23; - int64 lock_time = 24; - int64 start_time = 25; - NodeAddress refund_agent_node_address = 26; - RefundResultState refund_result_state = 27; - string counter_currency_extra_data = 28; - string uid = 29; - bool is_completed = 30; + int64 take_offer_date = 7; + int64 price = 8; + State state = 9; + PayoutState payout_state = 10; + DisputeState dispute_state = 11; + TradePeriodState period_state = 12; + Contract contract = 13; + string contract_as_json = 14; + bytes contract_hash = 15; + NodeAddress arbitrator_node_address = 16; + NodeAddress mediator_node_address = 17; + string error_message = 18; + string counter_currency_tx_id = 19; + repeated ChatMessage chat_message = 20; + MediationResultState mediation_result_state = 21; + int64 lock_time = 22; + int64 start_time = 23; + NodeAddress refund_agent_node_address = 24; + RefundResultState refund_result_state = 25; + string counter_currency_extra_data = 26; + string uid = 27; + bool is_completed = 28; } message BuyerAsMakerTrade {