From 48baa1e602fe5292962df1508e095207f1f6c284 Mon Sep 17 00:00:00 2001 From: woodser Date: Wed, 28 Dec 2022 10:02:37 +0000 Subject: [PATCH] use actual security deposits in dispute resolution --- .../bisq/core/api/CoreDisputesService.java | 6 ++-- .../core/btc/wallet/XmrWalletService.java | 2 +- .../core/support/dispute/DisputeManager.java | 15 ++++---- core/src/main/java/bisq/core/trade/Trade.java | 11 +++++- .../windows/DisputeSummaryWindow.java | 34 ++++++++++--------- 5 files changed, 39 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/bisq/core/api/CoreDisputesService.java b/core/src/main/java/bisq/core/api/CoreDisputesService.java index 4f8a9d1b83..4eb6081b4e 100644 --- a/core/src/main/java/bisq/core/api/CoreDisputesService.java +++ b/core/src/main/java/bisq/core/api/CoreDisputesService.java @@ -211,9 +211,9 @@ public class CoreDisputesService { */ public void applyPayoutAmountsToDisputeResult(DisputePayout payout, Dispute dispute, DisputeResult disputeResult, long customWinnerAmount) { Contract contract = dispute.getContract(); - Offer offer = new Offer(contract.getOfferPayload()); - Coin buyerSecurityDeposit = offer.getBuyerSecurityDeposit(); - Coin sellerSecurityDeposit = offer.getSellerSecurityDeposit(); + Trade trade = tradeManager.getTrade(dispute.getTradeId()); + Coin buyerSecurityDeposit = trade.getBuyerSecurityDeposit(); + Coin sellerSecurityDeposit = trade.getSellerSecurityDeposit(); Coin tradeAmount = contract.getTradeAmount(); if (payout == DisputePayout.BUYER_GETS_TRADE_AMOUNT) { disputeResult.setBuyerPayoutAmount(tradeAmount.add(buyerSecurityDeposit)); diff --git a/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java b/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java index f3c6014405..a85cbc1d86 100644 --- a/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java @@ -347,7 +347,7 @@ public class XmrWalletService { MoneroWallet wallet = getWallet(); synchronized (wallet) { - // binary search to maximize security deposit, thereby minimizing potential dust + // binary search to maximize security deposit and minimize potential dust MoneroTxWallet tradeTx = null; double appliedTolerance = 0.0; // percent of tolerance to apply, thereby decreasing security deposit double searchDiff = 1.0; // difference for next binary search diff --git a/core/src/main/java/bisq/core/support/dispute/DisputeManager.java b/core/src/main/java/bisq/core/support/dispute/DisputeManager.java index 6bf9f738e3..4ec3e8355c 100644 --- a/core/src/main/java/bisq/core/support/dispute/DisputeManager.java +++ b/core/src/main/java/bisq/core/support/dispute/DisputeManager.java @@ -43,7 +43,6 @@ import bisq.core.trade.Trade; import bisq.core.trade.TradeDataValidation; import bisq.core.trade.TradeManager; import bisq.core.trade.protocol.TradingPeer; -import bisq.core.util.ParsingUtils; import bisq.network.p2p.BootstrapListener; import bisq.network.p2p.NodeAddress; import bisq.network.p2p.P2PService; @@ -740,7 +739,7 @@ public abstract class DisputeManager> extends Sup if (!trade.isPayoutPublished()) { log.info("Arbitrator creating unsigned dispute payout tx for trade {}", trade.getId()); try { - MoneroTxWallet payoutTx = createDisputePayoutTx(trade, dispute, disputeResult, multisigWallet); + MoneroTxWallet payoutTx = createDisputePayoutTx(trade, dispute, disputeResult); trade.setPayoutTx(payoutTx); trade.setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); } catch (Exception e) { @@ -829,10 +828,10 @@ public abstract class DisputeManager> extends Sup // Utils /////////////////////////////////////////////////////////////////////////////////////////// - private MoneroTxWallet createDisputePayoutTx(Trade trade, Dispute dispute, DisputeResult disputeResult, MoneroWallet multisigWallet) { + private MoneroTxWallet createDisputePayoutTx(Trade trade, Dispute dispute, DisputeResult disputeResult) { - // multisig wallet must be synced - if (multisigWallet.isMultisigImportNeeded()) throw new RuntimeException("Arbitrator's wallet needs updated multisig hex to create payout tx which means a trader must have already broadcast the payout tx for trade " + dispute.getTradeId()); + // trade wallet must be synced + if (trade.getWallet().isMultisigImportNeeded()) throw new RuntimeException("Arbitrator's wallet needs updated multisig hex to create payout tx which means a trader must have already broadcast the payout tx for trade " + dispute.getTradeId()); // collect winner and loser payout address and amounts Contract contract = dispute.getContract(); @@ -847,7 +846,7 @@ public abstract class DisputeManager> extends Sup MoneroTxConfig txConfig = new MoneroTxConfig().setAccountIndex(0).setRelay(false); if (winnerPayoutAmount.compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(winnerPayoutAddress, winnerPayoutAmount.multiply(BigInteger.valueOf(9)).divide(BigInteger.valueOf(10))); // reduce payment amount to get fee of similar tx if (loserPayoutAmount.compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(loserPayoutAddress, loserPayoutAmount.multiply(BigInteger.valueOf(9)).divide(BigInteger.valueOf(10))); - MoneroTxWallet feeEstimateTx = multisigWallet.createTx(txConfig); + MoneroTxWallet feeEstimateTx = trade.getWallet().createTx(txConfig); // create payout tx by increasing estimated fee until successful MoneroTxWallet payoutTx = null; @@ -862,7 +861,7 @@ public abstract class DisputeManager> extends Sup } numAttempts++; try { - payoutTx = multisigWallet.createTx(txConfig); + payoutTx = trade.getWallet().createTx(txConfig); } catch (MoneroError e) { // exception expected // TODO: better way of estimating fee? } @@ -871,7 +870,7 @@ public abstract class DisputeManager> extends Sup log.info("Dispute payout transaction generated on attempt {}", numAttempts); // save updated multisig hex - trade.getSelf().setUpdatedMultisigHex(multisigWallet.exportMultisigHex()); + trade.getSelf().setUpdatedMultisigHex(trade.getWallet().exportMultisigHex()); return payoutTx; } diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java index 76400b2bb3..0dad74450c 100644 --- a/core/src/main/java/bisq/core/trade/Trade.java +++ b/core/src/main/java/bisq/core/trade/Trade.java @@ -67,6 +67,7 @@ import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; + import java.math.BigInteger; import java.time.Clock; import java.util.ArrayList; @@ -887,7 +888,7 @@ public abstract class Trade implements Tradable, Model { // by mediators and we keep the confirm disabled to avoid that the seller can complete the trade // without the penalty. long payoutAmountFromMediation = processModel.getSellerPayoutAmountFromMediation(); - long normalPayoutAmount = offer.getSellerSecurityDeposit().value; + long normalPayoutAmount = getSellerSecurityDeposit().value; return payoutAmountFromMediation < normalPayoutAmount; } @@ -1361,6 +1362,14 @@ public abstract class Trade implements Tradable, Model { return offer.getMakerFee(); } + public Coin getBuyerSecurityDeposit() { + return HavenoUtils.atomicUnitsToCoin(getWallet().getTx(this.getBuyer().getDepositTxHash()).getIncomingAmount()); + } + + public Coin getSellerSecurityDeposit() { + return HavenoUtils.atomicUnitsToCoin(getWallet().getTx(this.getSeller().getDepositTxHash()).getIncomingAmount()).subtract(getAmount()); + } + @Nullable public MoneroTxWallet getPayoutTx() { if (payoutTx == null) diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java index 064cdb975d..663e81eba2 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java @@ -17,7 +17,6 @@ package bisq.desktop.main.overlays.windows; -import bisq.desktop.components.AutoTooltipCheckBox; import bisq.desktop.components.AutoTooltipRadioButton; import bisq.desktop.components.HavenoTextArea; import bisq.desktop.components.InputTextField; @@ -31,7 +30,6 @@ import bisq.desktop.util.Layout; import bisq.core.btc.wallet.TradeWalletService; import bisq.core.btc.wallet.XmrWalletService; import bisq.core.locale.Res; -import bisq.core.offer.Offer; import bisq.core.support.dispute.Dispute; import bisq.core.support.dispute.DisputeList; import bisq.core.support.dispute.DisputeManager; @@ -40,6 +38,8 @@ import bisq.core.support.dispute.arbitration.ArbitrationManager; import bisq.core.support.dispute.mediation.MediationManager; import bisq.core.support.dispute.refund.RefundManager; import bisq.core.trade.Contract; +import bisq.core.trade.Trade; +import bisq.core.trade.TradeManager; import bisq.core.util.FormattingUtils; import bisq.core.util.ParsingUtils; import bisq.core.util.VolumeUtil; @@ -58,7 +58,6 @@ import com.google.inject.name.Named; import javafx.scene.Scene; import javafx.scene.control.Button; -import javafx.scene.control.CheckBox; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.control.TextArea; @@ -77,7 +76,6 @@ import javafx.beans.value.ChangeListener; import java.util.Date; import java.util.Optional; -import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @@ -90,9 +88,13 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j public class DisputeSummaryWindow extends Overlay { private final CoinFormatter formatter; + private final TradeManager tradeManager; private final ArbitrationManager arbitrationManager; private final MediationManager mediationManager; - private final CoreDisputesService disputesService; private Dispute dispute; + private final CoreDisputesService disputesService; + + private Dispute dispute; + private Trade trade; private ToggleGroup tradeAmountToggleGroup, reasonToggleGroup; private DisputeResult disputeResult; private RadioButton buyerGetsTradeAmountRadioButton, sellerGetsTradeAmountRadioButton, @@ -121,6 +123,7 @@ public class DisputeSummaryWindow extends Overlay { @Inject public DisputeSummaryWindow(@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, + TradeManager tradeManager, ArbitrationManager arbitrationManager, MediationManager mediationManager, XmrWalletService walletService, @@ -128,6 +131,7 @@ public class DisputeSummaryWindow extends Overlay { CoreDisputesService disputesService) { this.formatter = formatter; + this.tradeManager = tradeManager; this.arbitrationManager = arbitrationManager; this.mediationManager = mediationManager; this.disputesService = disputesService; @@ -137,6 +141,7 @@ public class DisputeSummaryWindow extends Overlay { public void show(Dispute dispute) { this.dispute = dispute; + this.trade = tradeManager.getTrade(dispute.getTradeId()); rowIndex = -1; width = 1150; @@ -277,11 +282,11 @@ public class DisputeSummaryWindow extends Overlay { VolumeUtil.formatVolumeWithCode(contract.getTradeVolume())); String securityDeposit = Res.getWithColAndCap("shared.buyer") + " " + - formatter.formatCoinWithCode(contract.getOfferPayload().getBuyerSecurityDeposit()) + + formatter.formatCoinWithCode(trade.getBuyerSecurityDeposit()) + " / " + Res.getWithColAndCap("shared.seller") + " " + - formatter.formatCoinWithCode(contract.getOfferPayload().getSellerSecurityDeposit()); + formatter.formatCoinWithCode(trade.getSellerSecurityDeposit()); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit); } @@ -345,10 +350,9 @@ public class DisputeSummaryWindow extends Overlay { Coin sellerAmount = ParsingUtils.parseToCoin(sellerPayoutAmountInputTextField.getText(), formatter); Contract contract = dispute.getContract(); Coin tradeAmount = contract.getTradeAmount(); - Offer offer = new Offer(contract.getOfferPayload()); Coin available = tradeAmount - .add(offer.getBuyerSecurityDeposit()) - .add(offer.getSellerSecurityDeposit()); + .add(trade.getBuyerSecurityDeposit()) + .add(trade.getSellerSecurityDeposit()); Coin totalAmount = buyerAmount.add(sellerAmount); boolean isRefundAgent = getDisputeManager(dispute) instanceof RefundManager; @@ -372,10 +376,9 @@ public class DisputeSummaryWindow extends Overlay { // } Contract contract = dispute.getContract(); - Offer offer = new Offer(contract.getOfferPayload()); Coin available = contract.getTradeAmount() - .add(offer.getBuyerSecurityDeposit()) - .add(offer.getSellerSecurityDeposit()); + .add(trade.getBuyerSecurityDeposit()) + .add(trade.getSellerSecurityDeposit()); Coin enteredAmount = ParsingUtils.parseToCoin(inputTextField.getText(), formatter); if (enteredAmount.compareTo(available) > 0) { enteredAmount = available; @@ -801,9 +804,8 @@ public class DisputeSummaryWindow extends Overlay { private void applyTradeAmountRadioButtonStates() { Contract contract = dispute.getContract(); - Offer offer = new Offer(contract.getOfferPayload()); - Coin buyerSecurityDeposit = offer.getBuyerSecurityDeposit(); - Coin sellerSecurityDeposit = offer.getSellerSecurityDeposit(); + Coin buyerSecurityDeposit = trade.getBuyerSecurityDeposit(); + Coin sellerSecurityDeposit = trade.getSellerSecurityDeposit(); Coin tradeAmount = contract.getTradeAmount(); Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();