security deposit is based on trade amount

This commit is contained in:
woodser 2023-10-31 14:57:49 -04:00
parent 7610d65d38
commit 23525d89ee
40 changed files with 215 additions and 158 deletions

View File

@ -64,7 +64,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest {
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals("3600", newOffer.getVolume());
assertEquals("3600", newOffer.getMinVolume());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(audAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals("AUD", newOffer.getCounterCurrencyCode());
@ -80,7 +81,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest {
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals("3600", newOffer.getVolume());
assertEquals("3600", newOffer.getMinVolume());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(audAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals("AUD", newOffer.getCounterCurrencyCode());
@ -110,7 +112,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest {
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals("3000", newOffer.getVolume());
assertEquals("3000", newOffer.getMinVolume());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(USD, newOffer.getCounterCurrencyCode());
@ -126,7 +129,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest {
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals("3000", newOffer.getVolume());
assertEquals("3000", newOffer.getMinVolume());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(USD, newOffer.getCounterCurrencyCode());
@ -156,7 +160,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest {
assertEquals(5_000_000, newOffer.getMinAmount());
assertEquals("2950", newOffer.getVolume());
assertEquals("1475", newOffer.getMinVolume());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(eurAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(EUR, newOffer.getCounterCurrencyCode());
@ -172,7 +177,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest {
assertEquals(5_000_000, newOffer.getMinAmount());
assertEquals("2950", newOffer.getVolume());
assertEquals("1475", newOffer.getMinVolume());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(eurAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(EUR, newOffer.getCounterCurrencyCode());

View File

@ -80,7 +80,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals(USD, newOffer.getCounterCurrencyCode());
@ -94,7 +95,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals(USD, newOffer.getCounterCurrencyCode());
@ -126,7 +128,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(nzdAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals("NZD", newOffer.getCounterCurrencyCode());
@ -140,7 +143,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(10_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(nzdAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals("NZD", newOffer.getCounterCurrencyCode());
@ -172,7 +176,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(5_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(gbpAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals("GBP", newOffer.getCounterCurrencyCode());
@ -186,7 +191,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(5_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(gbpAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals("GBP", newOffer.getCounterCurrencyCode());
@ -218,7 +224,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(5_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(brlAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals("BRL", newOffer.getCounterCurrencyCode());
@ -232,7 +239,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest {
assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct());
assertEquals(10_000_000, newOffer.getAmount());
assertEquals(5_000_000, newOffer.getMinAmount());
assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(brlAccount.getId(), newOffer.getPaymentAccountId());
assertEquals(BTC, newOffer.getBaseCurrencyCode());
assertEquals("BRL", newOffer.getCounterCurrencyCode());

View File

@ -75,7 +75,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertEquals("0.00500000", newOffer.getPrice());
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(75_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());
@ -91,7 +92,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertEquals("0.00500000", newOffer.getPrice());
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(75_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());
@ -119,7 +121,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertEquals("0.00500000", newOffer.getPrice());
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(50_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());
@ -135,7 +138,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertEquals("0.00500000", newOffer.getPrice());
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(50_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());
@ -169,7 +173,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(75_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());
@ -189,7 +194,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(75_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());
@ -218,7 +224,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertTrue(newOffer.getUseMarketBasedPrice());
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(50_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());
@ -233,7 +240,8 @@ public class CreateXMROffersTest extends AbstractOfferTest {
assertTrue(newOffer.getUseMarketBasedPrice());
assertEquals(100_000_000L, newOffer.getAmount());
assertEquals(50_000_000L, newOffer.getMinAmount());
assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit());
assertEquals(.15, newOffer.getBuyerSecurityDepositPct());
assertEquals(.15, newOffer.getSellerSecurityDepositPct());
assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId());
assertEquals(XMR, newOffer.getBaseCurrencyCode());
assertEquals(BTC, newOffer.getCounterCurrencyCode());

View File

@ -60,9 +60,9 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
@Nullable
protected final MixedTradeFeeColumn colMixedTradeFee;
@Nullable
protected final Column<Long> colBuyerDeposit;
protected final Column<Double> colBuyerDeposit;
@Nullable
protected final Column<Long> colSellerDeposit;
protected final Column<Double> colSellerDeposit;
@Nullable
protected final Column<String> colPaymentMethod;
@Nullable

View File

@ -61,8 +61,8 @@ class ClosedTradeTableBuilder extends AbstractTradeListBuilder {
colMixedTradeFee.addRow(toTradeFeeBtc.apply(t), false);
colBuyerDeposit.addRow(t.getOffer().getBuyerSecurityDeposit());
colSellerDeposit.addRow(t.getOffer().getSellerSecurityDeposit());
colBuyerDeposit.addRow(t.getOffer().getBuyerSecurityDepositPct());
colSellerDeposit.addRow(t.getOffer().getSellerSecurityDepositPct());
colOfferType.addRow(toOfferType.apply(t));
});
}

View File

@ -18,6 +18,7 @@
package haveno.cli.table.builder;
import haveno.cli.table.column.CryptoVolumeColumn;
import haveno.cli.table.column.DoubleColumn;
import haveno.cli.table.column.BooleanColumn;
import haveno.cli.table.column.BtcColumn;
import haveno.cli.table.column.Column;
@ -169,8 +170,8 @@ class TradeTableColumnSupplier {
: null;
};
final Function<String, Column<Long>> toSecurityDepositColumn = (name) -> isClosedTradeTblBuilder.get()
? new SatoshiColumn(name)
final Function<String, Column<Double>> toSecurityDepositColumn = (name) -> isClosedTradeTblBuilder.get()
? new DoubleColumn(name)
: null;
final Supplier<StringColumn> offerTypeColumn = () -> isTradeDetailTblBuilder.get()

View File

@ -156,7 +156,7 @@ public class CoreOffersService {
double marketPriceMargin,
long amountAsLong,
long minAmountAsLong,
double buyerSecurityDeposit,
double securityDeposit,
String triggerPriceAsString,
boolean reserveExactAmount,
String paymentAccountId,
@ -183,7 +183,7 @@ public class CoreOffersService {
price,
useMarketBasedPrice,
exactMultiply(marketPriceMargin, 0.01),
buyerSecurityDeposit,
securityDeposit,
paymentAccount);
verifyPaymentAccountIsValidForNewOffer(offer, paymentAccount);

View File

@ -54,8 +54,8 @@ public class OfferInfo implements Payload {
private final String minVolume;
private final long makerFee;
@Nullable
private final long buyerSecurityDeposit;
private final long sellerSecurityDeposit;
private final double buyerSecurityDepositPct;
private final double sellerSecurityDepositPct;
private final String triggerPrice;
private final String paymentAccountId;
private final String paymentMethodId;
@ -89,8 +89,8 @@ public class OfferInfo implements Payload {
this.volume = builder.getVolume();
this.minVolume = builder.getMinVolume();
this.makerFee = builder.getMakerFee();
this.buyerSecurityDeposit = builder.getBuyerSecurityDeposit();
this.sellerSecurityDeposit = builder.getSellerSecurityDeposit();
this.buyerSecurityDepositPct = builder.getBuyerSecurityDepositPct();
this.sellerSecurityDepositPct = builder.getSellerSecurityDepositPct();
this.triggerPrice = builder.getTriggerPrice();
this.paymentAccountId = builder.getPaymentAccountId();
this.paymentMethodId = builder.getPaymentMethodId();
@ -158,8 +158,8 @@ public class OfferInfo implements Payload {
.withVolume(roundedVolume)
.withMinVolume(roundedMinVolume)
.withMakerFee(offer.getMakerFee().longValueExact())
.withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().longValueExact())
.withSellerSecurityDeposit(offer.getSellerSecurityDeposit().longValueExact())
.withBuyerSecurityDepositPct(offer.getBuyerSecurityDepositPct())
.withSellerSecurityDepositPct(offer.getSellerSecurityDepositPct())
.withPaymentAccountId(offer.getMakerPaymentAccountId())
.withPaymentMethodId(offer.getPaymentMethod().getId())
.withPaymentMethodShortName(offer.getPaymentMethod().getShortName())
@ -191,8 +191,8 @@ public class OfferInfo implements Payload {
.setVolume(volume)
.setMinVolume(minVolume)
.setMakerFee(makerFee)
.setBuyerSecurityDeposit(buyerSecurityDeposit)
.setSellerSecurityDeposit(sellerSecurityDeposit)
.setBuyerSecurityDepositPct(buyerSecurityDepositPct)
.setSellerSecurityDepositPct(sellerSecurityDepositPct)
.setTriggerPrice(triggerPrice == null ? "0" : triggerPrice)
.setPaymentAccountId(paymentAccountId)
.setPaymentMethodId(paymentMethodId)
@ -226,8 +226,8 @@ public class OfferInfo implements Payload {
.withVolume(proto.getVolume())
.withMinVolume(proto.getMinVolume())
.withMakerFee(proto.getMakerFee())
.withBuyerSecurityDeposit(proto.getBuyerSecurityDeposit())
.withSellerSecurityDeposit(proto.getSellerSecurityDeposit())
.withBuyerSecurityDepositPct(proto.getBuyerSecurityDepositPct())
.withSellerSecurityDepositPct(proto.getSellerSecurityDepositPct())
.withTriggerPrice(proto.getTriggerPrice())
.withPaymentAccountId(proto.getPaymentAccountId())
.withPaymentMethodId(proto.getPaymentMethodId())

View File

@ -39,8 +39,8 @@ public final class OfferInfoBuilder {
private String volume;
private String minVolume;
private long makerFee;
private long buyerSecurityDeposit;
private long sellerSecurityDeposit;
private double buyerSecurityDepositPct;
private double sellerSecurityDepositPct;
private String triggerPrice;
private boolean isCurrencyForMakerFeeBtc;
private String paymentAccountId;
@ -112,13 +112,13 @@ public final class OfferInfoBuilder {
return this;
}
public OfferInfoBuilder withBuyerSecurityDeposit(long buyerSecurityDeposit) {
this.buyerSecurityDeposit = buyerSecurityDeposit;
public OfferInfoBuilder withBuyerSecurityDepositPct(double buyerSecurityDepositPct) {
this.buyerSecurityDepositPct = buyerSecurityDepositPct;
return this;
}
public OfferInfoBuilder withSellerSecurityDeposit(long sellerSecurityDeposit) {
this.sellerSecurityDeposit = sellerSecurityDeposit;
public OfferInfoBuilder withSellerSecurityDepositPct(double sellerSecurityDepositPct) {
this.sellerSecurityDepositPct = sellerSecurityDepositPct;
return this;
}

View File

@ -103,7 +103,7 @@ public class CreateOfferService {
Price fixedPrice,
boolean useMarketBasedPrice,
double marketPriceMargin,
double buyerSecurityDepositAsDouble,
double securityDepositAsDouble,
PaymentAccount paymentAccount) {
log.info("create and get offer with offerId={}, " +
@ -114,7 +114,7 @@ public class CreateOfferService {
"marketPriceMargin={}, " +
"amount={}, " +
"minAmount={}, " +
"buyerSecurityDeposit={}",
"securityDeposit={}",
offerId,
currencyCode,
direction,
@ -123,7 +123,7 @@ public class CreateOfferService {
marketPriceMargin,
amount,
minAmount,
buyerSecurityDepositAsDouble);
securityDepositAsDouble);
// verify fixed price xor market price with margin
if (fixedPrice != null) {
@ -161,10 +161,7 @@ public class CreateOfferService {
List<String> acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount);
String bankId = PaymentAccountUtil.getBankId(paymentAccount);
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
double sellerSecurityDepositAsDouble = getSellerSecurityDepositAsDouble(buyerSecurityDepositAsDouble);
BigInteger makerFee = HavenoUtils.getMakerFee(amount);
BigInteger buyerSecurityDeposit = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble);
BigInteger sellerSecurityDeposit = getSellerSecurityDeposit(amount, sellerSecurityDepositAsDouble);
long maxTradePeriod = paymentAccount.getMaxTradePeriod();
// reserved for future use cases
@ -180,7 +177,7 @@ public class CreateOfferService {
direction);
offerUtil.validateOfferData(
buyerSecurityDepositAsDouble,
securityDepositAsDouble,
paymentAccount,
currencyCode,
makerFee);
@ -206,8 +203,8 @@ public class CreateOfferService {
Version.VERSION,
xmrWalletService.getWallet().getHeight(),
makerFee.longValueExact(),
buyerSecurityDeposit.longValueExact(),
sellerSecurityDeposit.longValueExact(),
securityDepositAsDouble,
securityDepositAsDouble,
maxTradeLimit,
maxTradePeriod,
useAutoClose,

View File

@ -279,7 +279,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
// get the amount needed for the maker to reserve the offer
public BigInteger getReserveAmount() {
BigInteger reserveAmount = getDirection() == OfferDirection.BUY ? getBuyerSecurityDeposit() : getSellerSecurityDeposit();
BigInteger reserveAmount = getDirection() == OfferDirection.BUY ? getMaxBuyerSecurityDeposit() : getMaxSellerSecurityDeposit();
if (getDirection() == OfferDirection.SELL) reserveAmount = reserveAmount.add(getAmount());
reserveAmount = reserveAmount.add(getMakerFee());
return reserveAmount;
@ -289,12 +289,20 @@ public class Offer implements NetworkPayload, PersistablePayload {
return BigInteger.valueOf(offerPayload.getMakerFee());
}
public BigInteger getBuyerSecurityDeposit() {
return BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit());
public BigInteger getMaxBuyerSecurityDeposit() {
return offerPayload.getMaxBuyerSecurityDeposit();
}
public BigInteger getSellerSecurityDeposit() {
return BigInteger.valueOf(offerPayload.getSellerSecurityDeposit());
public BigInteger getMaxSellerSecurityDeposit() {
return offerPayload.getMaxSellerSecurityDeposit();
}
public double getBuyerSecurityDepositPct() {
return offerPayload.getBuyerSecurityDepositPct();
}
public double getSellerSecurityDepositPct() {
return offerPayload.getSellerSecurityDepositPct();
}
public BigInteger getMaxTradeLimit() {

View File

@ -28,6 +28,8 @@ import haveno.common.util.CollectionUtils;
import haveno.common.util.Hex;
import haveno.common.util.JsonExclude;
import haveno.common.util.Utilities;
import haveno.core.trade.HavenoUtils;
import haveno.core.xmr.wallet.Restrictions;
import haveno.network.p2p.NodeAddress;
import haveno.network.p2p.storage.payload.ExpirablePayload;
import haveno.network.p2p.storage.payload.ProtectedStoragePayload;
@ -39,6 +41,7 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
@ -130,8 +133,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
private final List<String> acceptedBankIds;
private final long blockHeightAtOfferCreation;
private final long makerFee;
private final long buyerSecurityDeposit;
private final long sellerSecurityDeposit;
private final double buyerSecurityDepositPct;
private final double sellerSecurityDepositPct;
private final long maxTradeLimit;
private final long maxTradePeriod;
@ -176,8 +179,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
String versionNr,
long blockHeightAtOfferCreation,
long makerFee,
long buyerSecurityDeposit,
long sellerSecurityDeposit,
double buyerSecurityDepositPct,
double sellerSecurityDepositPct,
long maxTradeLimit,
long maxTradePeriod,
boolean useAutoClose,
@ -217,8 +220,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
this.acceptedBankIds = acceptedBankIds;
this.blockHeightAtOfferCreation = blockHeightAtOfferCreation;
this.makerFee = makerFee;
this.buyerSecurityDeposit = buyerSecurityDeposit;
this.sellerSecurityDeposit = sellerSecurityDeposit;
this.buyerSecurityDepositPct = buyerSecurityDepositPct;
this.sellerSecurityDepositPct = sellerSecurityDepositPct;
this.maxTradeLimit = maxTradeLimit;
this.maxTradePeriod = maxTradePeriod;
this.useAutoClose = useAutoClose;
@ -261,8 +264,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
versionNr,
blockHeightAtOfferCreation,
makerFee,
buyerSecurityDeposit,
sellerSecurityDeposit,
buyerSecurityDepositPct,
sellerSecurityDepositPct,
maxTradeLimit,
maxTradePeriod,
useAutoClose,
@ -300,6 +303,24 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
return getBaseCurrencyCode().equals("XMR") ? getCounterCurrencyCode() : getBaseCurrencyCode();
}
public BigInteger getMaxBuyerSecurityDeposit() {
return getBuyerSecurityDepositForTradeAmount(BigInteger.valueOf(getAmount()));
}
public BigInteger getMaxSellerSecurityDeposit() {
return getSellerSecurityDepositForTradeAmount(BigInteger.valueOf(getAmount()));
}
public BigInteger getBuyerSecurityDepositForTradeAmount(BigInteger tradeAmount) {
BigInteger securityDepositUnadjusted = HavenoUtils.xmrToAtomicUnits(HavenoUtils.atomicUnitsToXmr(tradeAmount) * getBuyerSecurityDepositPct());
return Restrictions.getMinBuyerSecurityDeposit().max(securityDepositUnadjusted);
}
public BigInteger getSellerSecurityDepositForTradeAmount(BigInteger tradeAmount) {
BigInteger securityDepositUnadjusted = HavenoUtils.xmrToAtomicUnits(HavenoUtils.atomicUnitsToXmr(tradeAmount) * getSellerSecurityDepositPct());
return Restrictions.getMinSellerSecurityDeposit().max(securityDepositUnadjusted);
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
@ -323,8 +344,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
.setVersionNr(versionNr)
.setBlockHeightAtOfferCreation(blockHeightAtOfferCreation)
.setMakerFee(makerFee)
.setBuyerSecurityDeposit(buyerSecurityDeposit)
.setSellerSecurityDeposit(sellerSecurityDeposit)
.setBuyerSecurityDepositPct(buyerSecurityDepositPct)
.setSellerSecurityDepositPct(sellerSecurityDepositPct)
.setMaxTradeLimit(maxTradeLimit)
.setMaxTradePeriod(maxTradePeriod)
.setUseAutoClose(useAutoClose)
@ -377,8 +398,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
proto.getVersionNr(),
proto.getBlockHeightAtOfferCreation(),
proto.getMakerFee(),
proto.getBuyerSecurityDeposit(),
proto.getSellerSecurityDeposit(),
proto.getBuyerSecurityDepositPct(),
proto.getSellerSecurityDepositPct(),
proto.getMaxTradeLimit(),
proto.getMaxTradePeriod(),
proto.getUseAutoClose(),
@ -422,8 +443,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
",\r\n acceptedBankIds=" + acceptedBankIds +
",\r\n blockHeightAtOfferCreation=" + blockHeightAtOfferCreation +
",\r\n makerFee=" + makerFee +
",\r\n buyerSecurityDeposit=" + buyerSecurityDeposit +
",\r\n sellerSecurityDeposit=" + sellerSecurityDeposit +
",\r\n buyerSecurityDepositPct=" + buyerSecurityDepositPct +
",\r\n sellerSecurityDeposiPct=" + sellerSecurityDepositPct +
",\r\n maxTradeLimit=" + maxTradeLimit +
",\r\n maxTradePeriod=" + maxTradePeriod +
",\r\n useAutoClose=" + useAutoClose +
@ -460,8 +481,8 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
object.add("versionNr", context.serialize(offerPayload.getVersionNr()));
object.add("blockHeightAtOfferCreation", context.serialize(offerPayload.getBlockHeightAtOfferCreation()));
object.add("makerFee", context.serialize(offerPayload.getMakerFee()));
object.add("buyerSecurityDeposit", context.serialize(offerPayload.getBuyerSecurityDeposit()));
object.add("sellerSecurityDeposit", context.serialize(offerPayload.getSellerSecurityDeposit()));
object.add("buyerSecurityDepositPct", context.serialize(offerPayload.getBuyerSecurityDepositPct()));
object.add("sellerSecurityDepositPct", context.serialize(offerPayload.getSellerSecurityDepositPct()));
object.add("maxTradeLimit", context.serialize(offerPayload.getMaxTradeLimit()));
object.add("maxTradePeriod", context.serialize(offerPayload.getMaxTradePeriod()));
object.add("useAutoClose", context.serialize(offerPayload.isUseAutoClose()));

View File

@ -1167,9 +1167,17 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
return;
}
// verify security deposits are equal
if (offer.getBuyerSecurityDepositPct() != offer.getSellerSecurityDepositPct()) {
errorMessage = "Buyer and seller security deposits are not equal for offer " + request.offerId;
log.info(errorMessage);
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage);
return;
}
// verify maker's reserve tx (double spend, trade fee, trade amount, mining fee)
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit();
Tuple2<MoneroTx, BigInteger> txResult = xmrWalletService.verifyTradeTx(
offer.getId(),
tradeFee,
@ -1512,8 +1520,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
originalOfferPayload.getVersionNr(),
originalOfferPayload.getBlockHeightAtOfferCreation(),
originalOfferPayload.getMakerFee(),
originalOfferPayload.getBuyerSecurityDeposit(),
originalOfferPayload.getSellerSecurityDeposit(),
originalOfferPayload.getBuyerSecurityDepositPct(),
originalOfferPayload.getSellerSecurityDepositPct(),
originalOfferPayload.getMaxTradeLimit(),
originalOfferPayload.getMaxTradePeriod(),
originalOfferPayload.isUseAutoClose(),

View File

@ -52,7 +52,7 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
// create reserve tx
BigInteger makerFee = offer.getMakerFee();
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit();
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
XmrAddressEntry fundingEntry = model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).orElse(null);
Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex();

View File

@ -45,10 +45,10 @@ public class ValidateOffer extends Task<PlaceOfferModel> {
checkBINotNullOrZero(offer.getAmount(), "Amount");
checkBINotNullOrZero(offer.getMinAmount(), "MinAmount");
checkBINotNullOrZero(offer.getMakerFee(), "MakerFee");
checkBINotNullOrZero(offer.getBuyerSecurityDeposit(), "buyerSecurityDeposit");
checkBINotNullOrZero(offer.getSellerSecurityDeposit(), "sellerSecurityDeposit");
//checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model
checkBINotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit");
if (offer.getBuyerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Buyer security deposit must be positive but was " + offer.getBuyerSecurityDepositPct());
if (offer.getSellerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Seller security deposit must be positive but was " + offer.getSellerSecurityDepositPct());
// We remove those checks to be more flexible with future changes.
/*checkArgument(offer.getMakerFee().value >= FeeService.getMinMakerFee(offer.isCurrencyForMakerFeeBtc()).value,

View File

@ -100,8 +100,8 @@ public class TakeOfferModel implements Model {
this.useSavingsWallet = useSavingsWallet;
this.amount = tradeAmount.min(BigInteger.valueOf(getMaxTradeLimit()));
this.securityDeposit = offer.getDirection() == SELL
? offer.getBuyerSecurityDeposit()
: offer.getSellerSecurityDeposit();
? offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(amount)
: offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(amount);
this.takerFee = HavenoUtils.getTakerFee(amount);
calculateVolume();

View File

@ -1057,7 +1057,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
// The amount we would get if we do a new trade with current price
BigInteger potentialAmountAtDisputeOpening = priceAtDisputeOpening.getAmountByVolume(contract.getTradeVolume());
BigInteger buyerSecurityDeposit = BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit());
BigInteger buyerSecurityDeposit = offerPayload.getMaxBuyerSecurityDeposit();
BigInteger minRefundAtMediatedDispute = Restrictions.getMinRefundAtMediatedDispute();
// minRefundAtMediatedDispute is always larger as buyerSecurityDeposit at mediated payout, we ignore refund agent case here as there it can be 0.
BigInteger maxLossSecDeposit = buyerSecurityDeposit.subtract(minRefundAtMediatedDispute);

View File

@ -55,7 +55,7 @@ public abstract class BuyerTrade extends Trade {
@Override
public BigInteger getPayoutAmount() {
checkNotNull(getAmount(), "Invalid state: getTradeAmount() = null");
return checkNotNull(getOffer()).getBuyerSecurityDeposit().add(getAmount());
return getAmount().add(getBuyerSecurityDepositBeforeMiningFee());
}
@Override

View File

@ -85,11 +85,13 @@ public class ClosedTradableFormatter {
}
public String getBuyerSecurityDepositAsString(Tradable tradable) {
return HavenoUtils.formatXmr(tradable.getOffer().getBuyerSecurityDeposit());
Trade trade = castToTrade(tradable);
return HavenoUtils.formatXmr(trade.getBuyerSecurityDepositBeforeMiningFee());
}
public String getSellerSecurityDepositAsString(Tradable tradable) {
return HavenoUtils.formatXmr(tradable.getOffer().getSellerSecurityDeposit());
Trade trade = castToTrade(tradable);
return HavenoUtils.formatXmr(trade.getSellerSecurityDepositBeforeMiningFee());
}
public String getTradeFeeAsString(Tradable tradable, boolean appendCode) {

View File

@ -122,7 +122,7 @@ public class HavenoUtils {
}
public static BigInteger xmrToAtomicUnits(double xmr) {
return BigDecimal.valueOf(xmr).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).toBigInteger();
return BigDecimal.valueOf(xmr).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).setScale(8).toBigInteger();
}
public static long xmrToCentineros(double xmr) {
@ -176,6 +176,10 @@ public class HavenoUtils {
return applyDecimals(formatted, Math.max(2, decimalPlaces)) + (appendCode ? " XMR" : "");
}
public static String formatPercent(double percent) {
return (percent * 100) + "%";
}
private static String applyDecimals(String decimalStr, int decimalPlaces) {
if (decimalStr.contains(".")) return decimalStr + getNumZeros(decimalPlaces - (decimalStr.length() - decimalStr.indexOf(".") - 1));
else return decimalStr + "." + getNumZeros(decimalPlaces);

View File

@ -26,8 +26,6 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
import java.math.BigInteger;
import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j
public abstract class SellerTrade extends Trade {
SellerTrade(Offer offer,
@ -54,7 +52,7 @@ public abstract class SellerTrade extends Trade {
@Override
public BigInteger getPayoutAmount() {
return checkNotNull(getOffer()).getSellerSecurityDeposit();
return getSellerSecurityDepositBeforeMiningFee();
}
@Override

View File

@ -1628,6 +1628,14 @@ public abstract class Trade implements Tradable, Model {
return BigInteger.valueOf(takerFee);
}
public BigInteger getBuyerSecurityDepositBeforeMiningFee() {
return offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(getAmount());
}
public BigInteger getSellerSecurityDepositBeforeMiningFee() {
return offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(getAmount());
}
@Override
public BigInteger getTotalTxFee() {
return BigInteger.valueOf(totalTxFee);

View File

@ -17,7 +17,6 @@
package haveno.core.trade;
import haveno.core.offer.Offer;
import haveno.core.support.dispute.Dispute;
import haveno.core.xmr.wallet.BtcWalletService;
import lombok.Getter;
@ -36,6 +35,8 @@ import java.util.function.Consumer;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
// TODO: remove for XMR?
@Slf4j
public class TradeDataValidation {
@ -127,9 +128,8 @@ public class TradeDataValidation {
// Check amount
TransactionOutput output = delayedPayoutTx.getOutput(0);
Offer offer = checkNotNull(trade.getOffer());
BigInteger msOutputAmount = offer.getBuyerSecurityDeposit()
.add(offer.getSellerSecurityDeposit())
BigInteger msOutputAmount = trade.getBuyerSecurityDepositBeforeMiningFee()
.add(trade.getSellerSecurityDepositBeforeMiningFee())
.add(checkNotNull(trade.getAmount()));
if (!output.getValue().equals(msOutputAmount)) {

View File

@ -81,7 +81,7 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
boolean isFromBuyer = trader == trade.getBuyer();
BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : trade.getAmount();
BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
BigInteger securityDeposit = isFromBuyer ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee();
String depositAddress = processModel.getMultisigAddress();
// verify deposit tx

View File

@ -48,15 +48,15 @@ public class ArbitratorProcessReserveTx extends TradeTask {
runInterceptHook();
Offer offer = trade.getOffer();
InitTradeRequest request = (InitTradeRequest) processModel.getTradeMessage();
boolean isFromTaker = request.getSenderNodeAddress().equals(trade.getTaker().getNodeAddress());
boolean isFromBuyer = isFromTaker ? offer.getDirection() == OfferDirection.SELL : offer.getDirection() == OfferDirection.BUY;
boolean isFromMaker = request.getSenderNodeAddress().equals(trade.getMaker().getNodeAddress());
boolean isFromBuyer = isFromMaker ? offer.getDirection() == OfferDirection.BUY : offer.getDirection() == OfferDirection.SELL;
// TODO (woodser): if signer online, should never be called by maker
// process reserve tx with expected values
BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount();
BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
BigInteger tradeFee = isFromMaker ? trade.getMakerFee() : trade.getTakerFee();
BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : isFromMaker ? offer.getAmount() : trade.getAmount(); // maker reserve tx is for offer amount
BigInteger securityDeposit = isFromMaker ? isFromBuyer ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit() : isFromBuyer ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee();
Tuple2<MoneroTx, BigInteger> txResult;
try {
txResult = trade.getXmrWalletService().verifyTradeTx(
@ -71,11 +71,11 @@ public class ArbitratorProcessReserveTx extends TradeTask {
null);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error processing reserve tx from " + (isFromTaker ? "taker " : "maker ") + request.getSenderNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
throw new RuntimeException("Error processing reserve tx from " + (isFromMaker ? "maker " : "taker ") + request.getSenderNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
}
// save reserve tx to model
TradePeer trader = isFromTaker ? processModel.getTaker() : processModel.getMaker();
TradePeer trader = isFromMaker ? processModel.getMaker() : processModel.getTaker();
trader.setReserveTxHash(request.getReserveTxHash());
trader.setReserveTxHex(request.getReserveTxHex());
trader.setReserveTxKey(request.getReserveTxKey());

View File

@ -99,7 +99,7 @@ public class MaybeSendSignContractRequest extends TradeTask {
trade.getSelf().setPaymentAccountPayload(trade.getProcessModel().getPaymentAccountPayload(trade.getSelf().getPaymentAccountId()));
// TODO: security deposit should be based on trade amount, not max offer amount
BigInteger securityDeposit = trade instanceof BuyerTrade ? trade.getOffer().getBuyerSecurityDeposit() : trade.getOffer().getSellerSecurityDeposit();
BigInteger securityDeposit = trade instanceof BuyerTrade ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee();
trade.getSelf().setSecurityDeposit(securityDeposit.subtract(depositTx.getFee()));
// maker signs deposit hash nonce to avoid challenge protocol

View File

@ -41,8 +41,8 @@ public class TakerReserveTradeFunds extends TradeTask {
// create reserve tx
BigInteger takerFee = trade.getTakerFee();
BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getAmount() : BigInteger.valueOf(0);
BigInteger securityDeposit = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getSellerSecurityDeposit() : trade.getOffer().getBuyerSecurityDeposit();
BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getAmount() : BigInteger.valueOf(0);
BigInteger securityDeposit = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getSellerSecurityDepositBeforeMiningFee() : trade.getBuyerSecurityDepositBeforeMiningFee();
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(takerFee, sendAmount, securityDeposit, returnAddress, false, null);

View File

@ -13,7 +13,6 @@ import haveno.common.util.Utilities;
import haveno.core.api.AccountServiceListener;
import haveno.core.api.CoreAccountService;
import haveno.core.api.CoreMoneroConnectionsService;
import haveno.core.offer.Offer;
import haveno.core.trade.BuyerTrade;
import haveno.core.trade.HavenoUtils;
import haveno.core.trade.MakerTrade;
@ -385,11 +384,10 @@ public class XmrWalletService {
}
// create deposit tx
Offer offer = trade.getProcessModel().getOffer();
String multisigAddress = trade.getProcessModel().getMultisigAddress();
BigInteger tradeFee = trade instanceof MakerTrade ? trade.getOffer().getMakerFee() : trade.getTakerFee();
BigInteger sendAmount = trade instanceof BuyerTrade ? BigInteger.valueOf(0) : trade.getAmount();
BigInteger securityDeposit = trade instanceof BuyerTrade ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit(); // TODO: security deposit should be based on trade amount
BigInteger securityDeposit = trade instanceof BuyerTrade ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee();
long time = System.currentTimeMillis();
log.info("Creating deposit tx with multisig address={}", multisigAddress);
MoneroTxWallet depositTx = createTradeTx(tradeFee, sendAmount, securityDeposit, multisigAddress, reserveExactAmount, preferredSubaddressIndex);
@ -445,17 +443,6 @@ public class XmrWalletService {
.setSubtractFeeFrom(1)
.setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY)); // pay fee from security deposit
// check if tx uses exact input, since wallet2 can prefer to spend 2 outputs
if (reserveExactAmount) {
BigInteger exactInputAmount = tradeFee.add(sendAmount).add(securityDeposit);
BigInteger inputSum = BigInteger.valueOf(0);
for (MoneroOutputWallet txInput : tradeTx.getInputsWallet()) {
MoneroOutputWallet input = wallet.getOutputs(new MoneroOutputQuery().setKeyImage(txInput.getKeyImage())).get(0);
inputSum = inputSum.add(input.getAmount());
}
if (inputSum.compareTo(exactInputAmount) > 0) throw new RuntimeException("Cannot create transaction with exact input amount");
}
// freeze inputs
for (MoneroOutput input : tradeTx.getInputs()) wallet.freezeOutput(input.getKeyImage().getHex());
saveMainWallet();

View File

@ -291,8 +291,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
depositColumn.setComparator(Comparator.comparing(item -> {
boolean isSellOffer = item.getOffer().getDirection() == OfferDirection.SELL;
BigInteger deposit = isSellOffer ?
item.getOffer().getBuyerSecurityDeposit() :
item.getOffer().getSellerSecurityDeposit();
item.getOffer().getMaxBuyerSecurityDeposit() :
item.getOffer().getMaxSellerSecurityDeposit();
long amountValue = item.getOffer().getAmount().longValueExact();
if ((deposit == null || amountValue == 0)) {
@ -1015,8 +1015,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
super.updateItem(item, empty);
if (item != null && !empty) {
var isSellOffer = item.getOffer().getDirection() == OfferDirection.SELL;
var deposit = isSellOffer ? item.getOffer().getBuyerSecurityDeposit() :
item.getOffer().getSellerSecurityDeposit();
var deposit = isSellOffer ? item.getOffer().getMaxBuyerSecurityDeposit() :
item.getOffer().getMaxSellerSecurityDeposit();
if (deposit == null) {
setText(Res.get("shared.na"));
setGraphic(null);

View File

@ -460,11 +460,11 @@ class TakeOfferDataModel extends OfferDataModel {
}
public BigInteger getBuyerSecurityDeposit() {
return offer.getBuyerSecurityDeposit();
return offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(amount.get());
}
public BigInteger getSellerSecurityDeposit() {
return offer.getSellerSecurityDeposit();
return offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(amount.get());
}
public boolean isRoundedForAtmCash() {

View File

@ -154,11 +154,11 @@ public class ContractWindow extends Overlay<ContractWindow> {
VolumeUtil.formatVolumeWithCode(contract.getTradeVolume()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " +
HavenoUtils.formatXmr(offer.getBuyerSecurityDeposit(), true) +
HavenoUtils.formatXmr(offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(contract.getTradeAmount()), true) +
" / " +
Res.getWithColAndCap("shared.seller") +
" " +
HavenoUtils.formatXmr(offer.getSellerSecurityDeposit(), true);
HavenoUtils.formatXmr(offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(contract.getTradeAmount()), true);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
addConfirmationLabelTextField(gridPane,
++rowIndex,

View File

@ -334,11 +334,11 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
DisplayUtils.formatDateTime(offer.getDate()));
String value = Res.getWithColAndCap("shared.buyer") +
" " +
HavenoUtils.formatXmr(offer.getBuyerSecurityDeposit(), true) +
HavenoUtils.formatXmr(offer.getOfferPayload().getMaxBuyerSecurityDeposit(), true) +
" / " +
Res.getWithColAndCap("shared.seller") +
" " +
HavenoUtils.formatXmr(offer.getSellerSecurityDeposit(), true);
HavenoUtils.formatXmr(offer.getOfferPayload().getMaxSellerSecurityDeposit(), true);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
if (countryCode != null && !isF2F)

View File

@ -203,11 +203,11 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
DisplayUtils.formatDateTime(trade.getDate()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " +
HavenoUtils.formatXmr(offer.getBuyerSecurityDeposit(), true) +
HavenoUtils.formatXmr(offer.getMaxBuyerSecurityDeposit(), true) +
" / " +
Res.getWithColAndCap("shared.seller") +
" " +
HavenoUtils.formatXmr(offer.getSellerSecurityDeposit(), true);
HavenoUtils.formatXmr(offer.getMaxSellerSecurityDeposit(), true);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
NodeAddress arbitratorNodeAddress = trade.getArbitratorNodeAddress();

View File

@ -210,10 +210,10 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
return "BTC" + tradeFee;
}, Comparator.nullsFirst(Comparator.naturalOrder())));
buyerSecurityDepositColumn.setComparator(nullsFirstComparing(o ->
o.getTradable().getOffer() != null ? o.getTradable().getOffer().getBuyerSecurityDeposit() : null
o.getTradable().getOffer() != null ? o.getTradable().getOffer().getMaxBuyerSecurityDeposit() : null
));
sellerSecurityDepositColumn.setComparator(nullsFirstComparing(o ->
o.getTradable().getOffer() != null ? o.getTradable().getOffer().getSellerSecurityDeposit() : null
o.getTradable().getOffer() != null ? o.getTradable().getOffer().getMaxSellerSecurityDeposit() : null
));
stateColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getState));

View File

@ -95,7 +95,7 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
}
private double getBuyerSecurityAsPercent(Offer offer) {
BigInteger offerBuyerSecurityDeposit = getBoundedBuyerSecurityDeposit(offer.getBuyerSecurityDeposit());
BigInteger offerBuyerSecurityDeposit = getBoundedBuyerSecurityDeposit(offer.getMaxBuyerSecurityDeposit());
double offerBuyerSecurityDepositAsPercent = CoinUtil.getAsPercentPerBtc(offerBuyerSecurityDeposit,
offer.getAmount());
return Math.min(offerBuyerSecurityDepositAsPercent,

View File

@ -122,13 +122,15 @@ class EditOfferDataModel extends MutableOfferDataModel {
else
paymentAccount.setSelectedTradeCurrency(selectedTradeCurrency);
}
// TODO: update for XMR to use percent as double?
// If the security deposit got bounded because it was below the coin amount limit, it can be bigger
// by percentage than the restriction. We can't determine the percentage originally entered at offer
// creation, so just use the default value as it doesn't matter anyway.
double buyerSecurityDepositPercent = CoinUtil.getAsPercentPerBtc(offer.getBuyerSecurityDeposit(), offer.getAmount());
double buyerSecurityDepositPercent = CoinUtil.getAsPercentPerBtc(offer.getMaxBuyerSecurityDeposit(), offer.getAmount());
if (buyerSecurityDepositPercent > Restrictions.getMaxBuyerSecurityDepositAsPercent()
&& offer.getBuyerSecurityDeposit().equals(Restrictions.getMinBuyerSecurityDeposit()))
&& offer.getMaxBuyerSecurityDeposit().equals(Restrictions.getMinBuyerSecurityDeposit()))
buyerSecurityDepositPct.set(Restrictions.getDefaultBuyerSecurityDepositAsPercent());
else
buyerSecurityDepositPct.set(buyerSecurityDepositPercent);
@ -199,8 +201,8 @@ class EditOfferDataModel extends MutableOfferDataModel {
offerPayload.getVersionNr(),
offerPayload.getBlockHeightAtOfferCreation(),
offerPayload.getMakerFee(),
offerPayload.getBuyerSecurityDeposit(),
offerPayload.getSellerSecurityDeposit(),
offerPayload.getBuyerSecurityDepositPct(),
offerPayload.getSellerSecurityDepositPct(),
offerPayload.getMaxTradeLimit(),
offerPayload.getMaxTradePeriod(),
offerPayload.isUseAutoClose(),

View File

@ -304,8 +304,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
Trade trade = dataModel.getTrade();
if (offer != null && trade != null && trade.getAmount() != null) {
BigInteger securityDeposit = dataModel.isBuyer() ?
offer.getBuyerSecurityDeposit()
: offer.getSellerSecurityDeposit();
offer.getMaxBuyerSecurityDeposit()
: offer.getMaxSellerSecurityDeposit();
BigInteger minSecurityDeposit = dataModel.isBuyer() ?
Restrictions.getMinBuyerSecurityDeposit() :

View File

@ -85,7 +85,6 @@ import javafx.scene.text.Text;
import javafx.util.Callback;
import javafx.util.Duration;
import lombok.Getter;
import org.bitcoinj.core.Coin;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
@ -691,8 +690,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
String paymentMethod = Res.get(contract.getPaymentMethodId());
String currency = CurrencyUtil.getNameAndCode(contract.getOfferPayload().getCurrencyCode());
String tradeAmount = HavenoUtils.formatXmr(contract.getTradeAmount(), true);
String buyerDeposit = Coin.valueOf(contract.getOfferPayload().getBuyerSecurityDeposit()).toFriendlyString();
String sellerDeposit = Coin.valueOf(contract.getOfferPayload().getSellerSecurityDeposit()).toFriendlyString();
String buyerDeposit = HavenoUtils.formatXmr(contract.getOfferPayload().getBuyerSecurityDepositForTradeAmount(contract.getTradeAmount()), true);
String sellerDeposit = HavenoUtils.formatXmr(contract.getOfferPayload().getSellerSecurityDepositForTradeAmount(contract.getTradeAmount()), true);
stringBuilder.append("Payment method: ")
.append(paymentMethod)
.append("\n")
@ -702,7 +701,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
.append("Trade amount: ")
.append(tradeAmount)
.append("\n")
.append("Buyer/seller security deposit: ")
.append("Buyer/seller security deposit %: ")
.append(buyerDeposit)
.append("/")
.append(sellerDeposit)

View File

@ -523,16 +523,16 @@ message OfferInfo {
uint64 min_amount = 7 [jstype = JS_STRING];
string volume = 8;
string min_volume = 9;
uint64 buyer_security_deposit = 10 [jstype = JS_STRING];
string trigger_price = 11;
string payment_account_id = 12;
string payment_method_id = 13;
string payment_method_short_name = 14;
string base_currency_code = 15;
string counter_currency_code = 16;
uint64 date = 17;
string state = 18;
uint64 seller_security_deposit = 19 [jstype = JS_STRING];
double buyer_security_deposit_pct = 10;
double seller_security_deposit_pct = 11;
string trigger_price = 12;
string payment_account_id = 13;
string payment_method_id = 14;
string payment_method_short_name = 15;
string base_currency_code = 16;
string counter_currency_code = 17;
uint64 date = 18;
string state = 19;
uint64 maker_fee = 20 [jstype = JS_STRING];
bool is_activated = 21;
bool is_my_offer = 22;

View File

@ -623,8 +623,8 @@ message OfferPayload {
string version_nr = 19;
int64 block_height_at_offer_creation = 20;
int64 maker_fee = 21;
int64 buyer_security_deposit = 22;
int64 seller_security_deposit = 23;
double buyer_security_deposit_pct = 22;
double seller_security_deposit_pct = 23;
int64 max_trade_limit = 24;
int64 max_trade_period = 25;
bool use_auto_close = 26;