Skip to content

Commit

Permalink
Pick up WARNING_SENT* dispute states in TradeStepView
Browse files Browse the repository at this point in the history
When either of the trade peers publishes his warning tx, reflect that in
the info panel of the trade step view, providing a red "Redirect to
arbitration" or a (possibly greyed out) green "Claim trade collateral"
button, in place of the usual get-help/open-dispute button. Add four new
values to the 'TradeStepInfo.State' enum to distiguish whose warning tx
was published and whether the corresponding claim tx is still locked.
Provide (currently unimplemented) button action stubs to open a popup to
claim/redirect.

Also do some minor cleanup of 'TradeStepView' and make sure the method
'DisputeManager::checkForMediatedTradePayout' closes the mediation
ticket upon publishing of either warning tx, not just upon starting
arbitration or receiving a payout.
  • Loading branch information
stejbac committed Sep 22, 2024
1 parent 21b0c35 commit 463ab45
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 58 deletions.
26 changes: 16 additions & 10 deletions core/src/main/java/bisq/core/support/dispute/DisputeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,9 @@ protected void checkForMediatedTradePayout(Trade trade, Dispute dispute) {
disputedTradeUpdate(newValue.toString(), dispute, false);
}
});
// user rejected mediation after lockup period: opening arbitration
// user rejected mediation after lockup period: opening arbitration after peer redirects
trade.disputeStateProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.isArbitrated()) {
if (newValue.isEscalated()) {
disputedTradeUpdate(newValue.toString(), dispute, true);
}
});
Expand Down Expand Up @@ -453,28 +453,34 @@ protected void onOpenNewDisputeMessage(OpenNewDisputeMessage openNewDisputeMessa
protected void onPeerOpenedDisputeMessage(PeerOpenedDisputeMessage peerOpenedDisputeMessage) {
Dispute dispute = peerOpenedDisputeMessage.getDispute();
tradeManager.getTradeById(dispute.getTradeId()).ifPresentOrElse(
trade -> peerOpenedDisputeForTrade(peerOpenedDisputeMessage, dispute, trade),
() -> closedTradableManager.getTradableById(dispute.getTradeId()).ifPresentOrElse(
closedTradable -> newDisputeRevertsClosedTrade(peerOpenedDisputeMessage, dispute, (Trade)closedTradable),
() -> failedTradesManager.getTradeById(dispute.getTradeId()).ifPresent(
trade -> newDisputeRevertsFailedTrade(peerOpenedDisputeMessage, dispute, trade))));
trade -> peerOpenedDisputeForTrade(peerOpenedDisputeMessage, dispute, trade),
() -> closedTradableManager.getTradableById(dispute.getTradeId()).ifPresentOrElse(
closedTradable -> newDisputeRevertsClosedTrade(peerOpenedDisputeMessage, dispute, (Trade) closedTradable),
() -> failedTradesManager.getTradeById(dispute.getTradeId()).ifPresent(
trade -> newDisputeRevertsFailedTrade(peerOpenedDisputeMessage, dispute, trade))));
}

private void newDisputeRevertsFailedTrade(PeerOpenedDisputeMessage peerOpenedDisputeMessage, Dispute dispute, Trade trade) {
private void newDisputeRevertsFailedTrade(PeerOpenedDisputeMessage peerOpenedDisputeMessage,
Dispute dispute,
Trade trade) {
log.info("Peer dispute ticket received, reverting failed trade {} to pending", trade.getShortId());
failedTradesManager.removeTrade(trade);
tradeManager.addTradeToPendingTrades(trade);
peerOpenedDisputeForTrade(peerOpenedDisputeMessage, dispute, trade);
}

private void newDisputeRevertsClosedTrade(PeerOpenedDisputeMessage peerOpenedDisputeMessage, Dispute dispute, Trade trade) {
private void newDisputeRevertsClosedTrade(PeerOpenedDisputeMessage peerOpenedDisputeMessage,
Dispute dispute,
Trade trade) {
log.info("Peer dispute ticket received, reverting closed trade {} to pending", trade.getShortId());
closedTradableManager.remove(trade);
tradeManager.addTradeToPendingTrades(trade);
peerOpenedDisputeForTrade(peerOpenedDisputeMessage, dispute, trade);
}

private void peerOpenedDisputeForTrade(PeerOpenedDisputeMessage peerOpenedDisputeMessage, Dispute dispute, Trade trade) {
private void peerOpenedDisputeForTrade(PeerOpenedDisputeMessage peerOpenedDisputeMessage,
Dispute dispute,
Trade trade) {
String errorMessage = null;
T disputeList = getDisputeList();
if (disputeList == null) {
Expand Down
17 changes: 15 additions & 2 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ portfolio.pending.mediationResult.popup.info.v5=The mediator has suggested the f
If agreement is not possible, you will have to wait until {2} (block {3}) to Send a Warning to your trading peer, \
by broadcasting your warning transaction. The peer will then have a further 10 days (1440 blocks) to respond, by \
opening a second-round dispute with an arbitrator who will investigate the case again and do a payout based on their \
findings. If the peer does not respond in time, you can automatically claim the entire trade collateral.\n\n\
findings. If the peer does not respond in time, you can unilaterally claim the entire trade collateral.\n\n\
If the trade goes to arbitration the arbitrator will pay out the trade amount plus one peer''s security deposit. \
This means the total arbitration payout will be less than the mediation payout. \
Sending a warning or requesting arbitration is meant for exceptional circumstances. such as; \
Expand All @@ -1072,14 +1072,27 @@ portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver.v5=You have ac
Once the lock time is over on {0} (block {1}), you can Send a Warning to your trading peer, by broadcasting your \
warning transaction. The peer will then have a further 10 days (1440 blocks) to respond, by opening a second-round \
dispute with an arbitrator who will investigate the case again and do a payout based on their findings. If the peer \
does not respond in time, you can automatically claim the entire trade collateral.\n\n\
does not respond in time, you can unilaterally claim the entire trade collateral.\n\n\
You can find more details about the arbitration model at: \
[HYPERLINK:https://bisq.wiki/Dispute_resolution#Level_3:_Arbitration]
portfolio.pending.mediationResult.popup.reject=Reject
portfolio.pending.mediationResult.popup.openArbitration=Send to arbitration
portfolio.pending.mediationResult.popup.sendWarning=Send warning to peer
portfolio.pending.mediationResult.popup.alreadyAccepted=You've already accepted

portfolio.pending.warningSent.headline=Warning sent
portfolio.pending.warningSent.claimLocked.info=Your trading peer has until {0} (Block {1}) to redirect to arbitration. If \
they fail to do so by then, you can unilaterally claim the entire trade collateral.
portfolio.pending.warningSent.claimUnlocked.info=Your trading peer has failed to redirect to arbitration in time. You may \
now claim the entire trade collateral at any time before they attempt to redirect.
portfolio.pending.warningSent.button=Claim trade collateral
portfolio.pending.warningSentByPeer.headline=Warning sent by peer
portfolio.pending.warningSentByPeer.claimLocked.info=You have until {0} (Block {1}) to redirect to arbitration, before your \
trading peer can unilaterally claim the entire trade collateral.
portfolio.pending.warningSentByPeer.claimUnlocked.info=Your trading peer can unilaterally claim the entire trade collateral \
at any time. You must redirect to arbitration now to prevent this.
portfolio.pending.warningSentByPeer.button=Redirect to arbitration

portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\n\
Without this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. \
You can move this trade to failed trades.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@

@Slf4j
public class TradeStepInfo {

public enum State {
UNDEFINED,
SHOW_GET_HELP_BUTTON,
Expand All @@ -48,6 +47,10 @@ public enum State {
MEDIATION_RESULT,
MEDIATION_RESULT_SELF_ACCEPTED,
MEDIATION_RESULT_PEER_ACCEPTED,
WARNING_SENT_CLAIM_LOCKED,
WARNING_SENT_CLAIM_UNLOCKED,
WARNING_SENT_BY_PEER_CLAIM_LOCKED,
WARNING_SENT_BY_PEER_CLAIM_UNLOCKED,
IN_ARBITRATION_SELF_REQUESTED,
IN_ARBITRATION_PEER_REQUESTED,
IN_REFUND_REQUEST_SELF_REQUESTED,
Expand All @@ -66,7 +69,9 @@ public enum State {
private Trade trade;
@Getter
private State state = State.UNDEFINED;
@Setter
private Supplier<String> firstHalfOverWarnTextSupplier = () -> "";
@Setter
private Supplier<String> periodOverWarnTextSupplier = () -> "";

TradeStepInfo(TitledGroupBg titledGroupBg,
Expand All @@ -92,15 +97,7 @@ public void setOnAction(EventHandler<ActionEvent> e) {
button.setOnAction(e);
}

public void setFirstHalfOverWarnTextSupplier(Supplier<String> firstHalfOverWarnTextSupplier) {
this.firstHalfOverWarnTextSupplier = firstHalfOverWarnTextSupplier;
}

public void setPeriodOverWarnTextSupplier(Supplier<String> periodOverWarnTextSupplier) {
this.periodOverWarnTextSupplier = periodOverWarnTextSupplier;
}

public void setState(State state) {
public void setState(State state, Object... labelTextArguments) {
this.state = state;
switch (state) {
case UNDEFINED:
Expand Down Expand Up @@ -159,6 +156,42 @@ public void setState(State state) {
button.getStyleClass().add("action-button");
button.setDisable(false);
break;
case WARNING_SENT_CLAIM_LOCKED:
// grey button disabled
titledGroupBg.setText(Res.get("portfolio.pending.warningSent.headline"));
label.updateContent(Res.get("portfolio.pending.warningSent.claimLocked.info", labelTextArguments));
button.setText(Res.get("portfolio.pending.warningSent.button").toUpperCase());
button.setId(null);
button.getStyleClass().add("action-button");
button.setDisable(true);
break;
case WARNING_SENT_CLAIM_UNLOCKED:
// green button
titledGroupBg.setText(Res.get("portfolio.pending.warningSent.headline"));
label.updateContent(Res.get("portfolio.pending.warningSent.claimUnlocked.info"));
button.setText(Res.get("portfolio.pending.warningSent.button").toUpperCase());
button.setId(null);
button.getStyleClass().add("action-button");
button.setDisable(false);
break;
case WARNING_SENT_BY_PEER_CLAIM_LOCKED:
// red button
titledGroupBg.setText(Res.get("portfolio.pending.warningSentByPeer.headline"));
label.updateContent(Res.get("portfolio.pending.warningSentByPeer.claimLocked.info", labelTextArguments));
button.setText(Res.get("portfolio.pending.warningSentByPeer.button").toUpperCase());
button.setId("open-dispute-button");
button.getStyleClass().remove("action-button");
button.setDisable(false);
break;
case WARNING_SENT_BY_PEER_CLAIM_UNLOCKED:
// red button
titledGroupBg.setText(Res.get("portfolio.pending.warningSentByPeer.headline"));
label.updateContent(Res.get("portfolio.pending.warningSentByPeer.claimUnlocked.info"));
button.setText(Res.get("portfolio.pending.warningSentByPeer.button").toUpperCase());
button.setId("open-dispute-button");
button.getStyleClass().remove("action-button");
button.setDisable(false);
break;
case IN_REFUND_REQUEST_SELF_REQUESTED:
// red button
titledGroupBg.setText(Res.get("portfolio.pending.refundRequested"));
Expand Down
Loading

0 comments on commit 463ab45

Please sign in to comment.