Skip to content

Commit

Permalink
Implement rounding options for "Pay-By-Mail" payment type
Browse files Browse the repository at this point in the history
  • Loading branch information
wp07e committed Jul 1, 2024
1 parent 438e8d4 commit 5af9a9a
Show file tree
Hide file tree
Showing 26 changed files with 292 additions and 76 deletions.
4 changes: 4 additions & 0 deletions core/src/main/java/haveno/core/api/CoreApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ public void postOffer(String currencyCode,
double marketPriceMargin,
long amountAsLong,
long minAmountAsLong,
int roundTo,
double buyerSecurityDeposit,
String triggerPriceAsString,
boolean reserveExactAmount,
Expand All @@ -428,6 +429,7 @@ public void postOffer(String currencyCode,
marketPriceMargin,
amountAsLong,
minAmountAsLong,
roundTo,
buyerSecurityDeposit,
triggerPriceAsString,
reserveExactAmount,
Expand All @@ -444,6 +446,7 @@ public Offer editOffer(String offerId,
double marketPriceMargin,
BigInteger amount,
BigInteger minAmount,
Integer roundTo,
double buyerSecurityDeposit,
PaymentAccount paymentAccount) {
return coreOffersService.editOffer(offerId,
Expand All @@ -454,6 +457,7 @@ public Offer editOffer(String offerId,
marketPriceMargin,
amount,
minAmount,
roundTo,
buyerSecurityDeposit,
paymentAccount);
}
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/haveno/core/api/CoreOffersService.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ void postOffer(String currencyCode,
double marketPriceMargin,
long amountAsLong,
long minAmountAsLong,
int roundTo,
double securityDeposit,
String triggerPriceAsString,
boolean reserveExactAmount,
Expand All @@ -196,6 +197,7 @@ void postOffer(String currencyCode,
upperCaseCurrencyCode,
amount,
minAmount,
roundTo,
price,
useMarketBasedPrice,
exactMultiply(marketPriceMargin, 0.01),
Expand Down Expand Up @@ -223,13 +225,15 @@ Offer editOffer(String offerId,
double marketPriceMargin,
BigInteger amount,
BigInteger minAmount,
Integer roundTo,
double buyerSecurityDeposit,
PaymentAccount paymentAccount) {
return createOfferService.createAndGetOffer(offerId,
direction,
currencyCode.toUpperCase(),
amount,
minAmount,
roundTo,
price,
useMarketBasedPrice,
exactMultiply(marketPriceMargin, 0.01),
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/haveno/core/api/model/OfferInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class OfferInfo implements Payload {
private final double marketPriceMarginPct;
private final long amount;
private final long minAmount;
private final int roundTo;
private final String volume;
private final String minVolume;
private final double makerFeePct;
Expand Down Expand Up @@ -87,6 +88,7 @@ public OfferInfo(OfferInfoBuilder builder) {
this.marketPriceMarginPct = builder.getMarketPriceMarginPct();
this.amount = builder.getAmount();
this.minAmount = builder.getMinAmount();
this.roundTo = builder.getRoundTo();
this.makerFeePct = builder.getMakerFeePct();
this.takerFeePct = builder.getTakerFeePct();
this.penaltyFeePct = builder.getPenaltyFeePct();
Expand Down Expand Up @@ -158,6 +160,7 @@ private static OfferInfoBuilder getBuilder(Offer offer) {
.withMarketPriceMarginPct(marketPriceMarginAsPctLiteral)
.withAmount(offer.getAmount().longValueExact())
.withMinAmount(offer.getMinAmount().longValueExact())
.withRoundTo(offer.getRoundToSelection())
.withMakerFeePct(offer.getMakerFeePct())
.withTakerFeePct(offer.getTakerFeePct())
.withPenaltyFeePct(offer.getPenaltyFeePct())
Expand Down Expand Up @@ -194,6 +197,7 @@ public haveno.proto.grpc.OfferInfo toProtoMessage() {
.setMarketPriceMarginPct(marketPriceMarginPct)
.setAmount(amount)
.setMinAmount(minAmount)
.setRoundTo(roundTo)
.setVolume(volume)
.setMinVolume(minVolume)
.setMakerFeePct(makerFeePct)
Expand Down Expand Up @@ -231,6 +235,7 @@ public static OfferInfo fromProto(haveno.proto.grpc.OfferInfo proto) {
.withMarketPriceMarginPct(proto.getMarketPriceMarginPct())
.withAmount(proto.getAmount())
.withMinAmount(proto.getMinAmount())
.withRoundTo(proto.getRoundTo())
.withVolume(proto.getVolume())
.withMinVolume(proto.getMinVolume())
.withMakerFeePct(proto.getMakerFeePct())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public final class OfferInfoBuilder {
private double marketPriceMarginPct;
private long amount;
private long minAmount;
private int roundTo;
private String volume;
private String minVolume;
private double makerFeePct;
Expand Down Expand Up @@ -99,6 +100,11 @@ public OfferInfoBuilder withMinAmount(long minAmount) {
return this;
}

public OfferInfoBuilder withRoundTo(int roundTo) {
this.roundTo = roundTo;
return this;
}

public OfferInfoBuilder withMakerFeePct(double makerFeePct) {
this.makerFeePct = makerFeePct;
return this;
Expand Down Expand Up @@ -223,7 +229,7 @@ public OfferInfoBuilder withArbitratorSigner(String arbitratorSigner) {
this.arbitratorSigner = arbitratorSigner;
return this;
}

public OfferInfoBuilder withSplitOutputTxHash(String splitOutputTxHash) {
this.splitOutputTxHash = splitOutputTxHash;
return this;
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/haveno/core/offer/CreateOfferService.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public Offer createAndGetOffer(String offerId,
String currencyCode,
BigInteger amount,
BigInteger minAmount,
Integer roundTo,
Price fixedPrice,
boolean useMarketBasedPrice,
double marketPriceMargin,
Expand All @@ -109,6 +110,7 @@ public Offer createAndGetOffer(String offerId,
"currencyCode={}, " +
"direction={}, " +
"fixedPrice={}, " +
"roundTo={}, " +
"useMarketBasedPrice={}, " +
"marketPriceMargin={}, " +
"amount={}, " +
Expand All @@ -118,6 +120,7 @@ public Offer createAndGetOffer(String offerId,
currencyCode,
direction,
fixedPrice == null ? null : fixedPrice.getValue(),
roundTo,
useMarketBasedPrice,
marketPriceMargin,
amount,
Expand Down Expand Up @@ -189,6 +192,7 @@ public Offer createAndGetOffer(String offerId,
useMarketBasedPriceValue,
amountAsLong,
minAmountAsLong,
roundTo,
HavenoUtils.MAKER_FEE_PCT,
HavenoUtils.TAKER_FEE_PCT,
HavenoUtils.PENALTY_FEE_PCT,
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/haveno/core/offer/Offer.java
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,10 @@ public BigInteger getMinAmount() {
return BigInteger.valueOf(offerPayload.getMinAmount());
}

public Integer getRoundToSelection() {
return offerPayload.getRoundTo();
}

public boolean isRange() {
return offerPayload.getAmount() != offerPayload.getMinAmount();
}
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/haveno/core/offer/OfferBookService.java
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ private void doDumpStatistics() {
return new OfferForJson(offer.getDirection(),
offer.getCurrencyCode(),
offer.getMinAmount(),
offer.getRoundToSelection(),
offer.getAmount(),
offer.getPrice(),
offer.getDate(),
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/java/haveno/core/offer/OfferForJson.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import haveno.core.monetary.Volume;
import haveno.core.payment.payload.PaymentMethod;
import haveno.core.trade.HavenoUtils;
import lombok.Getter;
import lombok.Setter;
import org.bitcoinj.utils.MonetaryFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -40,6 +42,9 @@ public class OfferForJson {
public final OfferDirection direction;
public final String currencyCode;
public final long minAmount;
@Getter
@Setter
public final int roundTo;
public final long amount;
public final long price;
public final long date;
Expand Down Expand Up @@ -75,6 +80,7 @@ public class OfferForJson {
public OfferForJson(OfferDirection direction,
String currencyCode,
BigInteger minAmount,
Integer roundTo,
BigInteger amount,
@Nullable Price price,
Date date,
Expand All @@ -86,6 +92,7 @@ public OfferForJson(OfferDirection direction,
this.direction = direction;
this.currencyCode = currencyCode;
this.minAmount = minAmount.longValueExact();
this.roundTo = roundTo;
this.amount = amount.longValueExact();
this.price = price.getValue();
this.date = date.getTime();
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/haveno/core/offer/OfferPayload.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
protected final long price;
protected final long amount;
protected final long minAmount;
protected final int roundTo;
protected final String paymentMethodId;
protected final String makerPaymentAccountId;
protected final NodeAddress ownerNodeAddress;
Expand Down Expand Up @@ -171,6 +172,7 @@ public OfferPayload(String id,
boolean useMarketBasedPrice,
long amount,
long minAmount,
int roundTo,
double makerFeePct,
double takerFeePct,
double penaltyFeePct,
Expand Down Expand Up @@ -209,6 +211,7 @@ public OfferPayload(String id,
this.price = price;
this.amount = amount;
this.minAmount = minAmount;
this.roundTo = roundTo;
this.makerFeePct = makerFeePct;
this.takerFeePct = takerFeePct;
this.penaltyFeePct = penaltyFeePct;
Expand Down Expand Up @@ -260,6 +263,7 @@ public byte[] getSignatureHash() {
false,
amount,
minAmount,
roundTo,
makerFeePct,
takerFeePct,
penaltyFeePct,
Expand Down Expand Up @@ -350,6 +354,7 @@ public protobuf.StoragePayload toProtoMessage() {
.setUseMarketBasedPrice(useMarketBasedPrice)
.setAmount(amount)
.setMinAmount(minAmount)
.setRoundTo(roundTo)
.setMakerFeePct(makerFeePct)
.setTakerFeePct(takerFeePct)
.setPenaltyFeePct(penaltyFeePct)
Expand Down Expand Up @@ -402,6 +407,7 @@ public static OfferPayload fromProto(protobuf.OfferPayload proto) {
proto.getUseMarketBasedPrice(),
proto.getAmount(),
proto.getMinAmount(),
proto.getRoundTo(),
proto.getMakerFeePct(),
proto.getTakerFeePct(),
proto.getPenaltyFeePct(),
Expand Down Expand Up @@ -442,6 +448,7 @@ public String toString() {
",\r\n price=" + price +
",\r\n amount=" + amount +
",\r\n minAmount=" + minAmount +
",\r\n roundTo=" + roundTo +
",\r\n makerFeePct=" + makerFeePct +
",\r\n takerFeePct=" + takerFeePct +
",\r\n penaltyFeePct=" + penaltyFeePct +
Expand Down Expand Up @@ -493,6 +500,7 @@ public JsonElement serialize(OfferPayload offerPayload, Type type, JsonSerializa
object.add("useMarketBasedPrice", context.serialize(offerPayload.isUseMarketBasedPrice()));
object.add("amount", context.serialize(offerPayload.getAmount()));
object.add("minAmount", context.serialize(offerPayload.getMinAmount()));
object.add("roundTo", context.serialize(offerPayload.getRoundTo()));
object.add("makerFeePct", context.serialize(offerPayload.getMakerFeePct()));
object.add("takerFeePct", context.serialize(offerPayload.getTakerFeePct()));
object.add("penaltyFeePct", context.serialize(offerPayload.getPenaltyFeePct()));
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/java/haveno/core/offer/OpenOfferManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ private void doCancelOffer(@NotNull OpenOffer openOffer) {
Offer offer = openOffer.getOffer();
offer.setState(Offer.State.REMOVED);
openOffer.setState(OpenOffer.State.CANCELED);
removeOpenOffer(openOffer);
removeOpenOffer(openOffer);
closedTradableManager.add(openOffer); // TODO: don't add these to closed tradables?
xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId());
requestPersistence();
Expand Down Expand Up @@ -893,7 +893,7 @@ private void processScheduledOffers(TransactionResultHandler resultHandler, // T
}

private void processUnpostedOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {

// skip if already processing
if (openOffer.isProcessing()) {
resultHandler.handleResult(null);
Expand Down Expand Up @@ -1615,6 +1615,7 @@ private void maybeUpdatePersistedOffers() {
originalOfferPayload.isUseMarketBasedPrice(),
originalOfferPayload.getAmount(),
originalOfferPayload.getMinAmount(),
originalOfferPayload.getRoundTo(),
originalOfferPayload.getMakerFeePct(),
originalOfferPayload.getTakerFeePct(),
originalOfferPayload.getPenaltyFeePct(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme

// Cryptos
BLOCK_CHAINS = new PaymentMethod(BLOCK_CHAINS_ID, DAY, DEFAULT_TRADE_LIMIT_VERY_LOW_RISK, Arrays.asList()),

// Cryptos with 1 hour trade period
BLOCK_CHAINS_INSTANT = new PaymentMethod(BLOCK_CHAINS_INSTANT_ID, TimeUnit.HOURS.toMillis(1), DEFAULT_TRADE_LIMIT_VERY_LOW_RISK, Arrays.asList())
);
Expand Down Expand Up @@ -597,6 +597,10 @@ public static boolean isRoundedForAtmCash(String id) {
id.equals(PaymentMethod.HAL_CASH_ID);
}

public static boolean isRoundedForPBMCash(String id) {
return id.equals(PaymentMethod.PAY_BY_MAIL_ID);
}

public static boolean isFixedPriceOnly(String id) {
return id.equals(PaymentMethod.CASH_AT_ATM_ID) ||
id.equals(PaymentMethod.HAL_CASH_ID);
Expand Down
36 changes: 28 additions & 8 deletions core/src/main/java/haveno/core/util/VolumeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@
import haveno.core.offer.Offer;
import haveno.core.payment.payload.PaymentMethod;
import haveno.core.trade.HavenoUtils;
import lombok.extern.slf4j.Slf4j;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.MonetaryFormat;

import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

@Slf4j
public class VolumeUtil {

private static final MonetaryFormat VOLUME_FORMAT_UNIT = new MonetaryFormat().shift(0).minDecimals(0).repeatOptionalDecimals(0, 0);
Expand All @@ -61,13 +62,32 @@ public class VolumeUtil {
private static double EXPONENT = Math.pow(10, TraditionalMoney.SMALLEST_UNIT_EXPONENT); // 1000000000000 with precision 8

public static Volume getAdjustedVolume(Volume volumeByAmount, String paymentMethodId) {
if (PaymentMethod.isRoundedForAtmCash(paymentMethodId))
return VolumeUtil.getRoundedAtmCashVolume(volumeByAmount);
else if (CurrencyUtil.isVolumeRoundedToNearestUnit(volumeByAmount.getCurrencyCode()))
return VolumeUtil.getRoundedVolumeUnit(volumeByAmount);
else if (CurrencyUtil.isTraditionalCurrency(volumeByAmount.getCurrencyCode()))
return VolumeUtil.getRoundedVolumePrecise(volumeByAmount);
return volumeByAmount;
return getAdjustedVolume(volumeByAmount, paymentMethodId, 1);
}

public static Volume getAdjustedVolume(Volume volumeByAmount, String paymentMethodId, Integer factor) {
try {
if (PaymentMethod.isRoundedForAtmCash(paymentMethodId))
return VolumeUtil.getRoundedAtmCashVolume(volumeByAmount);
else if (PaymentMethod.isRoundedForPBMCash(paymentMethodId))
return VolumeUtil.getRoundedVolumeUnit(volumeByAmount, factor);
else if (CurrencyUtil.isVolumeRoundedToNearestUnit(volumeByAmount.getCurrencyCode()))
return VolumeUtil.getRoundedVolumeUnit(volumeByAmount);
else if (CurrencyUtil.isTraditionalCurrency(volumeByAmount.getCurrencyCode()))
return VolumeUtil.getRoundedVolumePrecise(volumeByAmount);
return volumeByAmount;
}
catch (NullPointerException e) {
if (factor != null) { //TODO: Figure out why 'factor' is null when initializing a "edit offer" operation
log.error(e.toString());
}
return null;
}
}

public static Volume getRoundedVolumeUnit(Volume volumeByAmount, Integer factor) {
// We want to get rounded to 1 unit of the currency, e.g. 1 EUR.
return getAdjustedVolumeUnit(volumeByAmount, factor);
}

public static Volume getRoundedVolumeUnit(Volume volumeByAmount) {
Expand Down
1 change: 1 addition & 0 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ shared.sellerSecurityDeposit=Seller Deposit
shared.amountWithCur=Amount in {0}
shared.volumeWithCur=Volume in {0}
shared.currency=Currency
shared.roundTo=Round To
shared.market=Market
shared.deviation=Deviation
shared.paymentMethod=Payment method
Expand Down
Loading

0 comments on commit 5af9a9a

Please sign in to comment.