re-enable triggered offers if within trigger price again

This commit is contained in:
woodser 2025-02-14 11:20:57 -05:00
parent 4a82c69507
commit 290a3738b7
6 changed files with 52 additions and 22 deletions

View File

@ -110,6 +110,10 @@ public final class OpenOffer implements Tradable {
@Getter
@Setter
transient int numProcessingAttempts = 0;
@Getter
@Setter
private boolean deactivatedByTrigger;
public OpenOffer(Offer offer) {
this(offer, 0, false);
}
@ -141,6 +145,7 @@ public final class OpenOffer implements Tradable {
this.reserveTxHex = openOffer.reserveTxHex;
this.reserveTxKey = openOffer.reserveTxKey;
this.challenge = openOffer.challenge;
this.deactivatedByTrigger = openOffer.deactivatedByTrigger;
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -158,7 +163,8 @@ public final class OpenOffer implements Tradable {
@Nullable String reserveTxHash,
@Nullable String reserveTxHex,
@Nullable String reserveTxKey,
@Nullable String challenge) {
@Nullable String challenge,
boolean deactivatedByTrigger) {
this.offer = offer;
this.state = state;
this.triggerPrice = triggerPrice;
@ -170,6 +176,7 @@ public final class OpenOffer implements Tradable {
this.reserveTxHex = reserveTxHex;
this.reserveTxKey = reserveTxKey;
this.challenge = challenge;
this.deactivatedByTrigger = deactivatedByTrigger;
// reset reserved state to available
if (this.state == State.RESERVED) setState(State.AVAILABLE);
@ -182,7 +189,8 @@ public final class OpenOffer implements Tradable {
.setTriggerPrice(triggerPrice)
.setState(protobuf.OpenOffer.State.valueOf(state.name()))
.setSplitOutputTxFee(splitOutputTxFee)
.setReserveExactAmount(reserveExactAmount);
.setReserveExactAmount(reserveExactAmount)
.setDeactivatedByTrigger(deactivatedByTrigger);
Optional.ofNullable(scheduledAmount).ifPresent(e -> builder.setScheduledAmount(scheduledAmount));
Optional.ofNullable(scheduledTxHashes).ifPresent(e -> builder.addAllScheduledTxHashes(scheduledTxHashes));
@ -207,7 +215,8 @@ public final class OpenOffer implements Tradable {
ProtoUtil.stringOrNullFromProto(proto.getReserveTxHash()),
ProtoUtil.stringOrNullFromProto(proto.getReserveTxHex()),
ProtoUtil.stringOrNullFromProto(proto.getReserveTxKey()),
ProtoUtil.stringOrNullFromProto(proto.getChallenge()));
ProtoUtil.stringOrNullFromProto(proto.getChallenge()),
proto.getDeactivatedByTrigger());
return openOffer;
}
@ -234,6 +243,14 @@ public final class OpenOffer implements Tradable {
public void setState(State state) {
this.state = state;
stateProperty.set(state);
if (state == State.AVAILABLE) {
deactivatedByTrigger = false;
}
}
public void deactivate(boolean deactivatedByTrigger) {
this.deactivatedByTrigger = deactivatedByTrigger;
setState(State.DEACTIVATED);
}
public ReadOnlyObjectProperty<State> stateProperty() {

View File

@ -604,13 +604,14 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
}
public void deactivateOpenOffer(OpenOffer openOffer,
boolean deactivatedByTrigger,
ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler) {
Offer offer = openOffer.getOffer();
if (openOffer.isAvailable()) {
offerBookService.deactivateOffer(offer.getOfferPayload(),
() -> {
openOffer.setState(OpenOffer.State.DEACTIVATED);
openOffer.deactivate(deactivatedByTrigger);
requestPersistence();
log.debug("deactivateOpenOffer, offerId={}", offer.getId());
resultHandler.handleResult();
@ -661,6 +662,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
if (openOffer.isAvailable()) {
deactivateOpenOffer(openOffer,
false,
resultHandler,
errorMessage -> {
offersToBeEdited.remove(openOffer.getId());

View File

@ -92,12 +92,11 @@ public class TriggerPriceService {
.filter(marketPrice -> openOffersByCurrency.containsKey(marketPrice.getCurrencyCode()))
.forEach(marketPrice -> {
openOffersByCurrency.get(marketPrice.getCurrencyCode()).stream()
.filter(openOffer -> !openOffer.isDeactivated())
.forEach(openOffer -> checkPriceThreshold(marketPrice, openOffer));
});
}
public static boolean wasTriggered(MarketPrice marketPrice, OpenOffer openOffer) {
public static boolean isTriggered(MarketPrice marketPrice, OpenOffer openOffer) {
Price price = openOffer.getOffer().getPrice();
if (price == null || marketPrice == null) {
return false;
@ -125,13 +124,12 @@ public class TriggerPriceService {
}
private void checkPriceThreshold(MarketPrice marketPrice, OpenOffer openOffer) {
if (wasTriggered(marketPrice, openOffer)) {
String currencyCode = openOffer.getOffer().getCurrencyCode();
int smallestUnitExponent = CurrencyUtil.isTraditionalCurrency(currencyCode) ?
TraditionalMoney.SMALLEST_UNIT_EXPONENT :
CryptoMoney.SMALLEST_UNIT_EXPONENT;
long triggerPrice = openOffer.getTriggerPrice();
if (openOffer.getState() == OpenOffer.State.AVAILABLE && isTriggered(marketPrice, openOffer)) {
log.info("Market price exceeded the trigger price of the open offer.\n" +
"We deactivate the open offer with ID {}.\nCurrency: {};\nOffer direction: {};\n" +
"Market price: {};\nTrigger price: {}",
@ -139,14 +137,26 @@ public class TriggerPriceService {
currencyCode,
openOffer.getOffer().getDirection(),
marketPrice.getPrice(),
MathUtils.scaleDownByPowerOf10(triggerPrice, smallestUnitExponent)
MathUtils.scaleDownByPowerOf10(openOffer.getTriggerPrice(), smallestUnitExponent)
);
openOfferManager.deactivateOpenOffer(openOffer, () -> {
openOfferManager.deactivateOpenOffer(openOffer, true, () -> {
}, errorMessage -> {
});
} else if (openOffer.getState() == OpenOffer.State.DEACTIVATED && openOffer.isDeactivatedByTrigger() && !isTriggered(marketPrice, openOffer)) {
log.info("Market price is back within the trigger price of the open offer.\n" +
"We reactivate the open offer with ID {}.\nCurrency: {};\nOffer direction: {};\n" +
"Market price: {};\nTrigger price: {}",
openOffer.getOffer().getShortId(),
currencyCode,
openOffer.getOffer().getDirection(),
marketPrice.getPrice(),
MathUtils.scaleDownByPowerOf10(openOffer.getTriggerPrice(), smallestUnitExponent)
);
openOfferManager.activateOpenOffer(openOffer, () -> {
}, errorMessage -> {
});
} else if (openOffer.getState() == OpenOffer.State.AVAILABLE) {
// TODO: check if open offer's reserve tx is failed or double spend seen
}
}

View File

@ -69,7 +69,7 @@ class OpenOffersDataModel extends ActivatableDataModel {
}
void onDeactivateOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
openOfferManager.deactivateOpenOffer(openOffer, resultHandler, errorMessageHandler);
openOfferManager.deactivateOpenOffer(openOffer, false, resultHandler, errorMessageHandler);
}
void onRemoveOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
@ -94,7 +94,7 @@ class OpenOffersDataModel extends ActivatableDataModel {
list.sort((o1, o2) -> o2.getOffer().getDate().compareTo(o1.getOffer().getDate()));
}
boolean wasTriggered(OpenOffer openOffer) {
return TriggerPriceService.wasTriggered(priceFeedService.getMarketPrice(openOffer.getOffer().getCurrencyCode()), openOffer);
boolean isTriggered(OpenOffer openOffer) {
return TriggerPriceService.isTriggered(priceFeedService.getMarketPrice(openOffer.getOffer().getCurrencyCode()), openOffer);
}
}

View File

@ -368,7 +368,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
}
private void onActivateOpenOffer(OpenOffer openOffer) {
if (model.isBootstrappedOrShowPopup() && !model.dataModel.wasTriggered(openOffer)) {
if (model.isBootstrappedOrShowPopup() && !model.dataModel.isTriggered(openOffer)) {
model.onActivateOpenOffer(openOffer,
() -> log.debug("Activate offer was successful"),
(message) -> {
@ -720,7 +720,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
checkBox.setPadding(new Insets(-7, 0, -7, 0));
checkBox.setGraphic(iconView);
}
checkBox.setDisable(model.dataModel.wasTriggered(openOffer));
checkBox.setDisable(model.dataModel.isTriggered(openOffer));
checkBox.setOnAction(event -> {
if (openOffer.isDeactivated()) {
onActivateOpenOffer(openOffer);
@ -798,7 +798,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
boolean triggerPriceSet = item.getOpenOffer().getTriggerPrice() > 0;
button.setVisible(triggerPriceSet);
if (model.dataModel.wasTriggered(item.getOpenOffer())) {
if (model.dataModel.isTriggered(item.getOpenOffer())) {
button.getGraphic().getStyleClass().add("warning");
button.setTooltip(new Tooltip(Res.get("openOffer.triggered")));
} else {

View File

@ -1421,6 +1421,7 @@ message OpenOffer {
string reserve_tx_hex = 10;
string reserve_tx_key = 11;
string challenge = 12;
bool deactivated_by_trigger = 13;
}
message Tradable {