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