Skip to content

Commit

Permalink
support passphrase-protected offers with no deposit (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
woodser committed Dec 11, 2024
1 parent b586bc5 commit e6023c0
Show file tree
Hide file tree
Showing 66 changed files with 3,270 additions and 461 deletions.
22 changes: 16 additions & 6 deletions core/src/main/java/haveno/core/api/CoreApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,12 @@ public void postOffer(String currencyCode,
double marketPriceMargin,
long amountAsLong,
long minAmountAsLong,
double buyerSecurityDeposit,
double securityDepositPct,
String triggerPriceAsString,
boolean reserveExactAmount,
String paymentAccountId,
boolean isPrivateOffer,
boolean requireBuyerAsTakerDeposit,
Consumer<Offer> resultHandler,
ErrorMessageHandler errorMessageHandler) {
coreOffersService.postOffer(currencyCode,
Expand All @@ -432,10 +434,12 @@ public void postOffer(String currencyCode,
marketPriceMargin,
amountAsLong,
minAmountAsLong,
buyerSecurityDeposit,
securityDepositPct,
triggerPriceAsString,
reserveExactAmount,
paymentAccountId,
isPrivateOffer,
requireBuyerAsTakerDeposit,
resultHandler,
errorMessageHandler);
}
Expand All @@ -448,8 +452,10 @@ public Offer editOffer(String offerId,
double marketPriceMargin,
BigInteger amount,
BigInteger minAmount,
double buyerSecurityDeposit,
PaymentAccount paymentAccount) {
double securityDepositPct,
PaymentAccount paymentAccount,
boolean isPrivateOffer,
boolean requireBuyerAsTakerDeposit) {
return coreOffersService.editOffer(offerId,
currencyCode,
direction,
Expand All @@ -458,8 +464,10 @@ public Offer editOffer(String offerId,
marketPriceMargin,
amount,
minAmount,
buyerSecurityDeposit,
paymentAccount);
securityDepositPct,
paymentAccount,
isPrivateOffer,
requireBuyerAsTakerDeposit);
}

public void cancelOffer(String id, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
Expand Down Expand Up @@ -535,9 +543,11 @@ public MarketDepthInfo getMarketDepth(String currencyCode) throws ExecutionExcep
public void takeOffer(String offerId,
String paymentAccountId,
long amountAsLong,
String passphrase,
Consumer<Trade> resultHandler,
ErrorMessageHandler errorMessageHandler) {
Offer offer = coreOffersService.getOffer(offerId);
offer.setPassphrase(passphrase);
coreTradesService.takeOffer(offer, paymentAccountId, amountAsLong, resultHandler, errorMessageHandler);
}

Expand Down
22 changes: 15 additions & 7 deletions core/src/main/java/haveno/core/api/CoreOffersService.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,12 @@ void postOffer(String currencyCode,
double marketPriceMargin,
long amountAsLong,
long minAmountAsLong,
double securityDeposit,
double securityDepositPct,
String triggerPriceAsString,
boolean reserveExactAmount,
String paymentAccountId,
boolean isPrivateOffer,
boolean requireBuyerAsTakerDeposit,
Consumer<Offer> resultHandler,
ErrorMessageHandler errorMessageHandler) {
coreWalletsService.verifyWalletsAreAvailable();
Expand All @@ -199,8 +201,10 @@ void postOffer(String currencyCode,
price,
useMarketBasedPrice,
exactMultiply(marketPriceMargin, 0.01),
securityDeposit,
paymentAccount);
securityDepositPct,
paymentAccount,
isPrivateOffer,
requireBuyerAsTakerDeposit);

verifyPaymentAccountIsValidForNewOffer(offer, paymentAccount);

Expand All @@ -223,8 +227,10 @@ Offer editOffer(String offerId,
double marketPriceMargin,
BigInteger amount,
BigInteger minAmount,
double buyerSecurityDeposit,
PaymentAccount paymentAccount) {
double securityDepositPct,
PaymentAccount paymentAccount,
boolean isPrivateOffer,
boolean requireBuyerAsTakerDeposit) {
return createOfferService.createAndGetOffer(offerId,
direction,
currencyCode.toUpperCase(),
Expand All @@ -233,8 +239,10 @@ Offer editOffer(String offerId,
price,
useMarketBasedPrice,
exactMultiply(marketPriceMargin, 0.01),
buyerSecurityDeposit,
paymentAccount);
securityDepositPct,
paymentAccount,
isPrivateOffer,
requireBuyerAsTakerDeposit);
}

void cancelOffer(String id, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
Expand Down
19 changes: 17 additions & 2 deletions core/src/main/java/haveno/core/api/model/OfferInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ public class OfferInfo implements Payload {
@Nullable
private final String splitOutputTxHash;
private final long splitOutputTxFee;
private final boolean isPrivateOffer;
private final String passphraseHash;
private final String passphrase;

public OfferInfo(OfferInfoBuilder builder) {
this.id = builder.getId();
Expand Down Expand Up @@ -111,6 +114,9 @@ public OfferInfo(OfferInfoBuilder builder) {
this.arbitratorSigner = builder.getArbitratorSigner();
this.splitOutputTxHash = builder.getSplitOutputTxHash();
this.splitOutputTxFee = builder.getSplitOutputTxFee();
this.isPrivateOffer = builder.isPrivateOffer();
this.passphraseHash = builder.getPassphraseHash();
this.passphrase = builder.getPassphrase();
}

public static OfferInfo toOfferInfo(Offer offer) {
Expand All @@ -137,6 +143,7 @@ public static OfferInfo toMyOfferInfo(OpenOffer openOffer) {
.withIsActivated(isActivated)
.withSplitOutputTxHash(openOffer.getSplitOutputTxHash())
.withSplitOutputTxFee(openOffer.getSplitOutputTxFee())
.withPassphrase(openOffer.getPassphrase())
.build();
}

Expand Down Expand Up @@ -177,7 +184,9 @@ private static OfferInfoBuilder getBuilder(Offer offer) {
.withPubKeyRing(offer.getOfferPayload().getPubKeyRing().toString())
.withVersionNumber(offer.getOfferPayload().getVersionNr())
.withProtocolVersion(offer.getOfferPayload().getProtocolVersion())
.withArbitratorSigner(offer.getOfferPayload().getArbitratorSigner() == null ? null : offer.getOfferPayload().getArbitratorSigner().getFullAddress());
.withArbitratorSigner(offer.getOfferPayload().getArbitratorSigner() == null ? null : offer.getOfferPayload().getArbitratorSigner().getFullAddress())
.withIsPrivateOffer(offer.isPrivateOffer())
.withPassphraseHash(offer.getPassphraseHash());
}

///////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -215,9 +224,12 @@ public haveno.proto.grpc.OfferInfo toProtoMessage() {
.setPubKeyRing(pubKeyRing)
.setVersionNr(versionNumber)
.setProtocolVersion(protocolVersion)
.setSplitOutputTxFee(splitOutputTxFee);
.setSplitOutputTxFee(splitOutputTxFee)
.setIsPrivateOffer(isPrivateOffer);
Optional.ofNullable(arbitratorSigner).ifPresent(builder::setArbitratorSigner);
Optional.ofNullable(splitOutputTxHash).ifPresent(builder::setSplitOutputTxHash);
Optional.ofNullable(passphraseHash).ifPresent(builder::setPassphraseHash);
Optional.ofNullable(passphrase).ifPresent(builder::setPassphrase);
return builder.build();
}

Expand Down Expand Up @@ -255,6 +267,9 @@ public static OfferInfo fromProto(haveno.proto.grpc.OfferInfo proto) {
.withArbitratorSigner(proto.getArbitratorSigner())
.withSplitOutputTxHash(proto.getSplitOutputTxHash())
.withSplitOutputTxFee(proto.getSplitOutputTxFee())
.withIsPrivateOffer(proto.getIsPrivateOffer())
.withPassphraseHash(proto.getPassphraseHash())
.withPassphrase(proto.getPassphrase())
.build();
}
}
16 changes: 8 additions & 8 deletions core/src/main/java/haveno/core/api/model/TradeInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,14 @@ public static TradeInfo toTradeInfo(Trade trade) {
.withAmount(trade.getAmount().longValueExact())
.withMakerFee(trade.getMakerFee().longValueExact())
.withTakerFee(trade.getTakerFee().longValueExact())
.withBuyerSecurityDeposit(trade.getBuyer().getSecurityDeposit() == null ? -1 : trade.getBuyer().getSecurityDeposit().longValueExact())
.withSellerSecurityDeposit(trade.getSeller().getSecurityDeposit() == null ? -1 : trade.getSeller().getSecurityDeposit().longValueExact())
.withBuyerDepositTxFee(trade.getBuyer().getDepositTxFee() == null ? -1 : trade.getBuyer().getDepositTxFee().longValueExact())
.withSellerDepositTxFee(trade.getSeller().getDepositTxFee() == null ? -1 : trade.getSeller().getDepositTxFee().longValueExact())
.withBuyerPayoutTxFee(trade.getBuyer().getPayoutTxFee() == null ? -1 : trade.getBuyer().getPayoutTxFee().longValueExact())
.withSellerPayoutTxFee(trade.getSeller().getPayoutTxFee() == null ? -1 : trade.getSeller().getPayoutTxFee().longValueExact())
.withBuyerPayoutAmount(trade.getBuyer().getPayoutAmount() == null ? -1 : trade.getBuyer().getPayoutAmount().longValueExact())
.withSellerPayoutAmount(trade.getSeller().getPayoutAmount() == null ? -1 : trade.getSeller().getPayoutAmount().longValueExact())
.withBuyerSecurityDeposit(trade.getBuyer().getSecurityDeposit().longValueExact())
.withSellerSecurityDeposit(trade.getSeller().getSecurityDeposit().longValueExact())
.withBuyerDepositTxFee(trade.getBuyer().getDepositTxFee().longValueExact())
.withSellerDepositTxFee(trade.getSeller().getDepositTxFee().longValueExact())
.withBuyerPayoutTxFee(trade.getBuyer().getPayoutTxFee().longValueExact())
.withSellerPayoutTxFee(trade.getSeller().getPayoutTxFee().longValueExact())
.withBuyerPayoutAmount(trade.getBuyer().getPayoutAmount().longValueExact())
.withSellerPayoutAmount(trade.getSeller().getPayoutAmount().longValueExact())
.withTotalTxFee(trade.getTotalTxFee().longValueExact())
.withPrice(toPreciseTradePrice.apply(trade))
.withVolume(toRoundedVolume.apply(trade))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public final class OfferInfoBuilder {
private String arbitratorSigner;
private String splitOutputTxHash;
private long splitOutputTxFee;
private boolean isPrivateOffer;
private String passphraseHash;
private String passphrase;

public OfferInfoBuilder withId(String id) {
this.id = id;
Expand Down Expand Up @@ -234,6 +237,21 @@ public OfferInfoBuilder withSplitOutputTxFee(long splitOutputTxFee) {
return this;
}

public OfferInfoBuilder withIsPrivateOffer(boolean isPrivateOffer) {
this.isPrivateOffer = isPrivateOffer;
return this;
}

public OfferInfoBuilder withPassphraseHash(String passphraseHash) {
this.passphraseHash = passphraseHash;
return this;
}

public OfferInfoBuilder withPassphrase(String passphrase) {
this.passphrase = passphrase;
return this;
}

public OfferInfo build() {
return new OfferInfo(this);
}
Expand Down
48 changes: 33 additions & 15 deletions core/src/main/java/haveno/core/offer/CreateOfferService.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ public Offer createAndGetOffer(String offerId,
Price fixedPrice,
boolean useMarketBasedPrice,
double marketPriceMargin,
double securityDepositAsDouble,
PaymentAccount paymentAccount) {

double securityDepositPct,
PaymentAccount paymentAccount,
boolean isPrivateOffer,
boolean requireBuyerAsTakerDeposit) {
log.info("create and get offer with offerId={}, " +
"currencyCode={}, " +
"direction={}, " +
Expand All @@ -113,7 +114,9 @@ public Offer createAndGetOffer(String offerId,
"marketPriceMargin={}, " +
"amount={}, " +
"minAmount={}, " +
"securityDeposit={}",
"securityDepositPct={}, " +
"isPrivateOffer={}, " +
"requireBuyerAsTakerDeposit={}",
offerId,
currencyCode,
direction,
Expand All @@ -122,7 +125,16 @@ public Offer createAndGetOffer(String offerId,
marketPriceMargin,
amount,
minAmount,
securityDepositAsDouble);
securityDepositPct,
isPrivateOffer,
requireBuyerAsTakerDeposit);


// verify buyer as taker security deposit
boolean isBuyerMaker = offerUtil.isBuyOffer(direction);
if (!isBuyerMaker && !isPrivateOffer && !requireBuyerAsTakerDeposit) {
throw new IllegalArgumentException("Buyer as taker deposit is required for public offers");
}

// verify fixed price xor market price with margin
if (fixedPrice != null) {
Expand Down Expand Up @@ -162,23 +174,28 @@ public Offer createAndGetOffer(String offerId,
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
long maxTradePeriod = paymentAccount.getMaxTradePeriod();

// reserved for future use cases
// Use null values if not set
boolean isPrivateOffer = false;
// generate one-time passphrase for private offer
String passphrase = null;
String passphraseHash = null;
if (isPrivateOffer) {
passphrase = HavenoUtils.generatePassphrase();
passphraseHash = HavenoUtils.getPassphraseHash(passphrase);
}

boolean useAutoClose = false;
boolean useReOpenAfterAutoClose = false;
long lowerClosePrice = 0;
long upperClosePrice = 0;
String hashOfChallenge = null;
Map<String, String> extraDataMap = offerUtil.getExtraDataMap(paymentAccount,
currencyCode,
direction);

offerUtil.validateOfferData(
securityDepositAsDouble,
securityDepositPct,
paymentAccount,
currencyCode);

boolean hasBuyerAsTakerWithoutDeposit = !isBuyerMaker && isPrivateOffer && !requireBuyerAsTakerDeposit;
OfferPayload offerPayload = new OfferPayload(offerId,
creationTime,
makerAddress,
Expand All @@ -189,11 +206,11 @@ public Offer createAndGetOffer(String offerId,
useMarketBasedPriceValue,
amountAsLong,
minAmountAsLong,
HavenoUtils.MAKER_FEE_PCT,
HavenoUtils.TAKER_FEE_PCT,
hasBuyerAsTakerWithoutDeposit ? HavenoUtils.MAKER_FEE_FOR_TAKER_WITHOUT_DEPOSIT_PCT : HavenoUtils.MAKER_FEE_PCT,
hasBuyerAsTakerWithoutDeposit ? 0d : HavenoUtils.TAKER_FEE_PCT,
HavenoUtils.PENALTY_FEE_PCT,
securityDepositAsDouble,
securityDepositAsDouble,
hasBuyerAsTakerWithoutDeposit ? 0d : securityDepositPct, // buyer as taker security deposit is optional for private offers
securityDepositPct,
baseCurrencyCode,
counterCurrencyCode,
paymentAccount.getPaymentMethod().getId(),
Expand All @@ -211,14 +228,15 @@ public Offer createAndGetOffer(String offerId,
upperClosePrice,
lowerClosePrice,
isPrivateOffer,
hashOfChallenge,
passphraseHash,
extraDataMap,
Version.TRADE_PROTOCOL_VERSION,
null,
null,
null);
Offer offer = new Offer(offerPayload);
offer.setPriceFeedService(priceFeedService);
offer.setPassphrase(passphrase);
return offer;
}

Expand Down
14 changes: 14 additions & 0 deletions core/src/main/java/haveno/core/offer/Offer.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ public enum State {
@Setter
transient private boolean isReservedFundsSpent;

@JsonExclude
@Getter
@Setter
@Nullable
transient private String passphrase;


///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
Expand Down Expand Up @@ -337,6 +343,14 @@ public double getSellerSecurityDepositPct() {
return offerPayload.getSellerSecurityDepositPct();
}

public boolean isPrivateOffer() {
return offerPayload.isPrivateOffer();
}

public String getPassphraseHash() {
return offerPayload.getPassphraseHash();
}

public BigInteger getMaxTradeLimit() {
return BigInteger.valueOf(offerPayload.getMaxTradeLimit());
}
Expand Down
Loading

0 comments on commit e6023c0

Please sign in to comment.