diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index e6acd109b0..cad7f9d5a5 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -568,8 +568,8 @@ public class CoreApi { coreTradesService.confirmPaymentReceived(tradeId, resultHandler, errorMessageHandler); } - public void keepFunds(String tradeId) { - coreTradesService.keepFunds(tradeId); + public void closeTrade(String tradeId) { + coreTradesService.closeTrade(tradeId); } public void withdrawFunds(String tradeId, String address, String memo) { diff --git a/core/src/main/java/bisq/core/api/CoreTradesService.java b/core/src/main/java/bisq/core/api/CoreTradesService.java index 3264b2683f..3365ed771c 100644 --- a/core/src/main/java/bisq/core/api/CoreTradesService.java +++ b/core/src/main/java/bisq/core/api/CoreTradesService.java @@ -155,7 +155,7 @@ class CoreTradesService { } } - void keepFunds(String tradeId) { + void closeTrade(String tradeId) { coreWalletsService.verifyWalletsAreAvailable(); coreWalletsService.verifyEncryptedWalletIsUnlocked(); 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 07cdf01e3e..a1cabc4395 100644 --- a/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java @@ -812,6 +812,13 @@ public class XmrWalletService { return getAddressEntryListAsImmutableList().stream().filter(addressEntry -> XmrAddressEntry.Context.AVAILABLE == addressEntry.getContext()).collect(Collectors.toList()); } + public List getAddressEntriesForOpenOffer() { + return getAddressEntryListAsImmutableList().stream() + .filter(addressEntry -> XmrAddressEntry.Context.OFFER_FUNDING == addressEntry.getContext() || + XmrAddressEntry.Context.RESERVED_FOR_TRADE == addressEntry.getContext()) + .collect(Collectors.toList()); + } + public List getAddressEntriesForTrade() { return getAddressEntryListAsImmutableList().stream() .filter(addressEntry -> XmrAddressEntry.Context.MULTI_SIG == addressEntry.getContext() || XmrAddressEntry.Context.TRADE_PAYOUT == addressEntry.getContext()) diff --git a/core/src/main/java/bisq/core/offer/OpenOfferManager.java b/core/src/main/java/bisq/core/offer/OpenOfferManager.java index 0b39f4bc4c..df2060183a 100644 --- a/core/src/main/java/bisq/core/offer/OpenOfferManager.java +++ b/core/src/main/java/bisq/core/offer/OpenOfferManager.java @@ -248,7 +248,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe private void cleanUpAddressEntries() { Set openOffersIdSet = openOffers.getList().stream().map(OpenOffer::getId).collect(Collectors.toSet()); - btcWalletService.getAddressEntriesForOpenOffer().stream() + xmrWalletService.getAddressEntriesForOpenOffer().stream() .filter(e -> !openOffersIdSet.contains(e.getOfferId())) .forEach(e -> { log.warn("We found an outdated addressEntry for openOffer {} (openOffers does not contain that " + @@ -568,8 +568,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe openOffer.setState(OpenOffer.State.CANCELED); openOffers.remove(openOffer); closedTradableManager.add(openOffer); - log.info("onRemoved offerId={}", offer.getId()); xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId()); + log.info("onRemoved offerId={}", offer.getId()); requestPersistence(); } diff --git a/core/src/main/java/bisq/core/support/dispute/arbitration/ArbitrationManager.java b/core/src/main/java/bisq/core/support/dispute/arbitration/ArbitrationManager.java index 139d3f128b..3c00c503b4 100644 --- a/core/src/main/java/bisq/core/support/dispute/arbitration/ArbitrationManager.java +++ b/core/src/main/java/bisq/core/support/dispute/arbitration/ArbitrationManager.java @@ -407,11 +407,11 @@ public final class ArbitrationManager extends DisputeManager tradeListeners; // notified on fully validated trade messages transient MoneroWalletListener depositTxListener; + transient MoneroWalletListener payoutTxListener; transient Boolean makerDepositLocked; // null when unknown, true while locked, false when unlocked transient Boolean takerDepositLocked; + @Nullable + transient private MoneroTxWallet payoutTx; + @Getter + @Setter + private String payoutTxId; + @Nullable + @Getter + @Setter + private String payoutTxHex; + @Getter + @Setter + private String payoutTxKey; private Long startTime; // cache /////////////////////////////////////////////////////////////////////////////////////////// @@ -547,6 +557,8 @@ public abstract class Trade implements Tradable, Model { Optional.ofNullable(counterCurrencyTxId).ifPresent(e -> builder.setCounterCurrencyTxId(counterCurrencyTxId)); Optional.ofNullable(mediationResultState).ifPresent(e -> builder.setMediationResultState(MediationResultState.toProtoMessage(mediationResultState))); Optional.ofNullable(refundResultState).ifPresent(e -> builder.setRefundResultState(RefundResultState.toProtoMessage(refundResultState))); + Optional.ofNullable(payoutTxHex).ifPresent(e -> builder.setPayoutTxHex(payoutTxHex)); + Optional.ofNullable(payoutTxKey).ifPresent(e -> builder.setPayoutTxHex(payoutTxKey)); Optional.ofNullable(delayedPayoutTxBytes).ifPresent(e -> builder.setDelayedPayoutTxBytes(ByteString.copyFrom(delayedPayoutTxBytes))); Optional.ofNullable(counterCurrencyExtraData).ifPresent(e -> builder.setCounterCurrencyExtraData(counterCurrencyExtraData)); Optional.ofNullable(assetTxProofResult).ifPresent(e -> builder.setAssetTxProofResult(assetTxProofResult.name())); @@ -560,6 +572,8 @@ public abstract class Trade implements Tradable, Model { trade.setPeriodState(TradePeriodState.fromProto(proto.getPeriodState())); trade.setTakerFeeTxId(ProtoUtil.stringOrNullFromProto(proto.getTakerFeeTxId())); trade.setPayoutTxId(ProtoUtil.stringOrNullFromProto(proto.getPayoutTxId())); + trade.setPayoutTxHex(ProtoUtil.stringOrNullFromProto(proto.getPayoutTxHex())); + trade.setPayoutTxKey(ProtoUtil.stringOrNullFromProto(proto.getPayoutTxKey())); trade.setContract(proto.hasContract() ? Contract.fromProto(proto.getContract(), coreProtoResolver) : null); trade.setContractAsJson(ProtoUtil.stringOrNullFromProto(proto.getContractAsJson())); trade.setContractHash(ProtoUtil.byteArrayOrNullFromProto(proto.getContractHash())); @@ -705,7 +719,7 @@ public abstract class Trade implements Tradable, Model { BigInteger buyerDepositAmount = multisigWallet.getTx(getBuyer().getDepositTxHash()).getIncomingAmount(); BigInteger tradeAmount = ParsingUtils.coinToAtomicUnits(getAmount()); - // parse payout tx + // describe payout tx MoneroTxSet describedTxSet = multisigWallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(payoutTxHex)); if (describedTxSet.getTxs() == null || describedTxSet.getTxs().size() != 1) throw new RuntimeException("Bad payout tx"); // TODO (woodser): test nack MoneroTxWallet payoutTx = describedTxSet.getTxs().get(0); @@ -747,8 +761,8 @@ public abstract class Trade implements Tradable, Model { } // update trade state - getSelf().setPayoutTxHex(payoutTxHex); setPayoutTx(describedTxSet.getTxs().get(0)); + setPayoutTxHex(payoutTxHex); // submit payout tx if (publish) { @@ -807,17 +821,17 @@ public abstract class Trade implements Tradable, Model { // handle deposit txs seen if (txs.size() == 2) { - setStatePublished(); + setStateDepositsPublished(); boolean makerFirst = txs.get(0).getHash().equals(processModel.getMaker().getDepositTxHash()); getMaker().setDepositTx(makerFirst ? txs.get(0) : txs.get(1)); getTaker().setDepositTx(makerFirst ? txs.get(1) : txs.get(0)); // check if deposit txs unlocked if (txs.get(0).isConfirmed() && txs.get(1).isConfirmed()) { - setStateConfirmed(); + setStateDepositsConfirmed(); long unlockHeight = Math.max(txs.get(0).getHeight(), txs.get(1).getHeight()) + XmrWalletService.NUM_BLOCKS_UNLOCK; if (havenoWallet.getHeight() >= unlockHeight) { - setStateUnlocked(); + setStateDepositsUnlocked(); return; } } @@ -844,7 +858,7 @@ public abstract class Trade implements Tradable, Model { // skip if deposit txs not seen if (txs.size() != 2) return; - setStatePublished(); + setStateDepositsPublished(); // update deposit txs boolean makerFirst = txs.get(0).getHash().equals(processModel.getMaker().getDepositTxHash()); @@ -854,7 +868,7 @@ public abstract class Trade implements Tradable, Model { // check if deposit txs confirmed and compute unlock height if (txs.size() == 2 && txs.get(0).isConfirmed() && txs.get(1).isConfirmed() && unlockHeight == null) { log.info("Multisig deposits confirmed for trade {}", getId()); - setStateConfirmed(); + setStateDepositsConfirmed(); unlockHeight = Math.max(txs.get(0).getHeight(), txs.get(1).getHeight()) + XmrWalletService.NUM_BLOCKS_UNLOCK; } @@ -863,7 +877,7 @@ public abstract class Trade implements Tradable, Model { log.info("Multisig deposits unlocked for trade {}", getId()); xmrWalletService.removeWalletListener(depositTxListener); // remove listener when notified depositTxListener = null; // prevent re-applying trade state in subsequent requests - setStateUnlocked(); + setStateDepositsUnlocked(); } } }; @@ -872,6 +886,51 @@ public abstract class Trade implements Tradable, Model { xmrWalletService.addWalletListener(depositTxListener); } + public void listenForPayoutTx() { + log.info("Listening for payout tx for trade {}", getId()); + + // check if payout tx already seen + if (getState().ordinal() >= Trade.State.PAYOUT_TX_SEEN_IN_NETWORK.ordinal()) { + log.warn("We had a payout tx already set. tradeId={}, state={}", getId(), getState()); + return; + } + + // get payout address entry + Optional optionalPayoutEntry = xmrWalletService.getAddressEntry(getId(), XmrAddressEntry.Context.TRADE_PAYOUT); + if (!optionalPayoutEntry.isPresent()) throw new RuntimeException("Trade does not have address entry for payout"); + XmrAddressEntry payoutEntry = optionalPayoutEntry.get(); + + // watch for payout tx on loop + new Thread(() -> { // TODO: use thread manager + boolean found = false; + while (!found) { + if (getPayoutTxKey() != null) { + + // get txs to payout address + List txs = xmrWalletService.getWallet().getTxs(new MoneroTxQuery() + .setTransferQuery(new MoneroTransferQuery() + .setAccountIndex(0) + .setSubaddressIndex(payoutEntry.getSubaddressIndex()) + .setIsIncoming(true))); + + // check for payout tx + for (MoneroTxWallet tx : txs) { + MoneroCheckTx txCheck = xmrWalletService.getWallet().checkTxKey(tx.getHash(), getPayoutTxKey(), payoutEntry.getAddressString()); + if (txCheck.isGood() && txCheck.receivedAmount.compareTo(new BigInteger("0")) > 0) { + found = true; + setPayoutTx(tx); + setStateIfValidTransitionTo(Trade.State.PAYOUT_TX_SEEN_IN_NETWORK); + return; + } + } + } + + // wait to loop + GenUtils.waitFor(xmrWalletService.getConnectionsService().getDefaultRefreshPeriodMs()); + } + }).start(); + } + @Nullable public MoneroTx getTakerDepositTx() { String depositTxHash = getProcessModel().getTaker().getDepositTxHash(); @@ -1045,6 +1104,7 @@ public abstract class Trade implements Tradable, Model { public void setPayoutTx(MoneroTxWallet payoutTx) { this.payoutTx = payoutTx; payoutTxId = payoutTx.getHash(); + payoutTxKey = payoutTx.getKey(); } public void setErrorMessage(String errorMessage) { @@ -1275,7 +1335,6 @@ public abstract class Trade implements Tradable, Model { } public boolean isPayoutPublished() { - if (getState() == Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG) return true; // TODO: this is a hack because seller has not seen signed payout tx. replace when payout process refactored return getState().getPhase().ordinal() >= Phase.PAYOUT_PUBLISHED.ordinal() || isWithdrawn(); } @@ -1397,15 +1456,15 @@ public abstract class Trade implements Tradable, Model { return tradeVolumeProperty; } - private void setStatePublished() { - if (!isDepositPublished()) setState(State.DEPOSIT_TXS_SEEN_IN_BLOCKCHAIN); + private void setStateDepositsPublished() { + if (!isDepositPublished()) setState(State.DEPOSIT_TXS_SEEN_IN_NETWORK); } - private void setStateConfirmed() { + private void setStateDepositsConfirmed() { if (!isDepositConfirmed()) setState(State.DEPOSIT_TXS_CONFIRMED_IN_BLOCKCHAIN); } - private void setStateUnlocked() { + private void setStateDepositsUnlocked() { if (!isDepositUnlocked()) setState(State.DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN); } diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 9da4dcdf80..793613f811 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -284,7 +284,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi xmrWalletService.getAddressEntriesForAvailableBalanceStream() .filter(addressEntry -> addressEntry.getOfferId() != null) .forEach(addressEntry -> { - log.warn("Swapping pending OFFER_FUNDING entries at startup. offerId={}", addressEntry.getOfferId()); + log.warn("Swapping pending {} entries at startup. offerId={}", addressEntry.getContext(), addressEntry.getOfferId()); xmrWalletService.swapTradeEntryToAvailableEntry(addressEntry.getOfferId(), XmrAddressEntry.Context.OFFER_FUNDING); }); @@ -837,6 +837,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // If trade was completed (closed without fault but might be closed by a dispute) we move it to the closed trades public void onTradeCompleted(Trade trade) { + if (trade.getState() == Trade.State.WITHDRAW_COMPLETED) return; closedTradableManager.add(trade); trade.setState(Trade.State.WITHDRAW_COMPLETED); maybeRemoveTrade(trade); diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java index e11337ed06..970fdce233 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java @@ -17,6 +17,9 @@ package bisq.core.trade.protocol; +import bisq.common.UserThread; +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; import bisq.core.trade.BuyerTrade; import bisq.core.trade.Trade; import bisq.core.trade.messages.PaymentAccountKeyResponse; @@ -25,20 +28,16 @@ import bisq.core.trade.messages.SignContractResponse; import bisq.core.trade.messages.TradeMessage; import bisq.core.trade.protocol.FluentProtocol.Condition; import bisq.core.trade.protocol.tasks.ApplyFilter; -import bisq.core.trade.protocol.tasks.BuyerSendPayoutTxPublishedMessage; import bisq.core.trade.protocol.tasks.BuyerPreparePaymentSentMessage; +import bisq.core.trade.protocol.tasks.BuyerProcessPaymentAccountKeyResponse; import bisq.core.trade.protocol.tasks.BuyerProcessPaymentReceivedMessage; import bisq.core.trade.protocol.tasks.BuyerSendPaymentAccountKeyRequestToArbitrator; import bisq.core.trade.protocol.tasks.BuyerSendPaymentSentMessage; -import bisq.core.trade.protocol.tasks.BuyerSetupPayoutTxListener; -import bisq.core.trade.protocol.tasks.BuyerProcessPaymentAccountKeyResponse; +import bisq.core.trade.protocol.tasks.BuyerSendPayoutTxPublishedMessage; import bisq.core.trade.protocol.tasks.SetupDepositTxsListener; +import bisq.core.trade.protocol.tasks.SetupPayoutTxListener; import bisq.core.util.Validator; import bisq.network.p2p.NodeAddress; -import bisq.common.UserThread; -import bisq.common.handlers.ErrorMessageHandler; -import bisq.common.handlers.ResultHandler; - import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; @@ -70,17 +69,20 @@ public abstract class BuyerProtocol extends DisputeProtocol { // request key to decrypt seller's payment account payload after first confirmation sendPaymentAccountKeyRequestIfWhenNeeded(BuyerEvent.STARTUP, false); + // listen for deposit txs given(anyPhase(Trade.Phase.DEPOSIT_REQUESTED, Trade.Phase.DEPOSITS_PUBLISHED, Trade.Phase.DEPOSITS_CONFIRMED) .with(BuyerEvent.STARTUP)) .setup(tasks(SetupDepositTxsListener.class)) .executeTasks(); + // listen for payout tx given(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED) .with(BuyerEvent.STARTUP)) - .setup(tasks(BuyerSetupPayoutTxListener.class)) // TODO (woodser): mirror deposit listener setup? + .setup(tasks(SetupPayoutTxListener.class)) .executeTasks(); - given(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED) + // send payment sent message + given(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED) // TODO: remove payment received phase? .anyState(Trade.State.BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG, Trade.State.BUYER_SEND_FAILED_PAYMENT_SENT_MSG) .with(BuyerEvent.STARTUP)) .setup(tasks(BuyerSendPaymentSentMessage.class)) diff --git a/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java index 163e95c885..5fe790d151 100644 --- a/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java @@ -22,6 +22,7 @@ import bisq.core.trade.Trade; import bisq.core.trade.messages.PaymentSentMessage; import bisq.core.trade.messages.SignContractResponse; import bisq.core.trade.messages.TradeMessage; +import bisq.core.trade.protocol.BuyerProtocol.BuyerEvent; import bisq.core.trade.protocol.FluentProtocol.Condition; import bisq.core.trade.protocol.tasks.ApplyFilter; import bisq.core.trade.protocol.tasks.SellerMaybeSendPayoutTxPublishedMessage; @@ -30,6 +31,7 @@ import bisq.core.trade.protocol.tasks.SellerProcessPaymentSentMessage; import bisq.core.trade.protocol.tasks.SellerSendPaymentReceivedMessage; import bisq.core.trade.protocol.tasks.SellerSendPaymentAccountPayloadKey; import bisq.core.trade.protocol.tasks.SetupDepositTxsListener; +import bisq.core.trade.protocol.tasks.SetupPayoutTxListener; import bisq.network.p2p.NodeAddress; import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ResultHandler; @@ -60,11 +62,17 @@ public abstract class SellerProtocol extends DisputeProtocol { sendPaymentAccountPayloadKeyWhenConfirmed(SellerEvent.STARTUP); } - // listen for changes to deposit txs + // listen for deposit txs given(anyPhase(Trade.Phase.DEPOSIT_REQUESTED, Trade.Phase.DEPOSITS_PUBLISHED, Trade.Phase.DEPOSITS_CONFIRMED) .with(SellerEvent.STARTUP)) .setup(tasks(SetupDepositTxsListener.class)) .executeTasks(); + + // listen for payout tx + given(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED) + .with(BuyerEvent.STARTUP)) + .setup(tasks(SetupPayoutTxListener.class)) + .executeTasks(); } @Override diff --git a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java index e05d7448f0..f4d358385e 100644 --- a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java @@ -335,7 +335,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D latchTrade(); Validator.checkTradeId(processModel.getOfferId(), response); processModel.setTradeMessage(response); - expect(anyState(Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST, Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS, Trade.State.DEPOSIT_TXS_SEEN_IN_BLOCKCHAIN) + expect(anyState(Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST, Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS, Trade.State.DEPOSIT_TXS_SEEN_IN_NETWORK) .with(response) .from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress() .setup(tasks( diff --git a/core/src/main/java/bisq/core/trade/protocol/TradingPeer.java b/core/src/main/java/bisq/core/trade/protocol/TradingPeer.java index e7c6fc6577..2261be44c2 100644 --- a/core/src/main/java/bisq/core/trade/protocol/TradingPeer.java +++ b/core/src/main/java/bisq/core/trade/protocol/TradingPeer.java @@ -124,10 +124,6 @@ public final class TradingPeer implements PersistablePayload { @Nullable private String depositTxKey; @Nullable - transient private MoneroTxWallet payoutTx; - @Nullable - private String payoutTxHex; - @Nullable private String updatedMultisigHex; public TradingPeer() { @@ -164,7 +160,6 @@ public final class TradingPeer implements PersistablePayload { Optional.ofNullable(preparedMultisigHex).ifPresent(e -> builder.setPreparedMultisigHex(preparedMultisigHex)); Optional.ofNullable(madeMultisigHex).ifPresent(e -> builder.setMadeMultisigHex(madeMultisigHex)); Optional.ofNullable(exchangedMultisigHex).ifPresent(e -> builder.setExchangedMultisigHex(exchangedMultisigHex)); - Optional.ofNullable(payoutTxHex).ifPresent(e -> builder.setPayoutTxHex(payoutTxHex)); Optional.ofNullable(depositTxHash).ifPresent(e -> builder.setDepositTxHash(depositTxHash)); Optional.ofNullable(depositTxHex).ifPresent(e -> builder.setDepositTxHex(depositTxHex)); Optional.ofNullable(depositTxKey).ifPresent(e -> builder.setDepositTxKey(depositTxKey)); @@ -216,7 +211,6 @@ public final class TradingPeer implements PersistablePayload { tradingPeer.setDepositTxHash(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHash())); tradingPeer.setDepositTxHex(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHex())); tradingPeer.setDepositTxKey(ProtoUtil.stringOrNullFromProto(proto.getDepositTxKey())); - tradingPeer.setPayoutTxHex(ProtoUtil.stringOrNullFromProto(proto.getPayoutTxHex())); tradingPeer.setUpdatedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex())); return tradingPeer; } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java index dd4139923c..ca7b436dba 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java @@ -65,11 +65,16 @@ public class BuyerPreparePaymentSentMessage extends TradeTask { // create payout tx if we have seller's updated multisig hex if (trade.getTradingPeer().getUpdatedMultisigHex() != null) { + + // create payout tx log.info("Buyer creating unsigned payout tx"); multisigWallet.importMultisigHex(trade.getTradingPeer().getUpdatedMultisigHex()); MoneroTxWallet payoutTx = trade.createPayoutTx(); - trade.getBuyer().setPayoutTx(payoutTx); - trade.getBuyer().setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + trade.setPayoutTx(payoutTx); + trade.setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + + // start listening for published payout tx + trade.listenForPayoutTx(); } else { if (trade.getSelf().getUpdatedMultisigHex() == null) trade.getSelf().setUpdatedMultisigHex(multisigWallet.exportMultisigHex()); // only export multisig hex once } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerProcessPaymentReceivedMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerProcessPaymentReceivedMessage.java index 3c7183f8b0..ff64d71717 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerProcessPaymentReceivedMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerProcessPaymentReceivedMessage.java @@ -59,7 +59,7 @@ public class BuyerProcessPaymentReceivedMessage extends TradeTask { if (trade.getPhase().ordinal() < Trade.Phase.PAYOUT_PUBLISHED.ordinal()) { // publish payout tx if signed. otherwise verify, sign, and publish payout tx - boolean previouslySigned = trade.getBuyer().getPayoutTxHex() != null; + boolean previouslySigned = trade.getPayoutTxHex() != null; if (previouslySigned) { log.info("Buyer publishing signed payout tx from seller"); XmrWalletService walletService = processModel.getProvider().getXmrWalletService(); @@ -67,14 +67,17 @@ public class BuyerProcessPaymentReceivedMessage extends TradeTask { List txHashes = multisigWallet.submitMultisigTxHex(message.getPayoutTxHex()); trade.setPayoutTx(multisigWallet.getTx(txHashes.get(0))); XmrWalletService.printTxs("payoutTx received from peer", trade.getPayoutTx()); - trade.setState(Trade.State.BUYER_RECEIVED_PAYOUT_TX_PUBLISHED_MSG); + trade.setStateIfValidTransitionTo(Trade.State.BUYER_RECEIVED_PAYOUT_TX_PUBLISHED_MSG); walletService.closeMultisigWallet(trade.getId()); } else { log.info("Buyer verifying, signing, and publishing seller's payout tx"); trade.verifyPayoutTx(message.getPayoutTxHex(), true, true); - trade.setState(Trade.State.BUYER_PUBLISHED_PAYOUT_TX); - // TODO (woodser): send PayoutTxPublishedMessage to arbitrator and seller + trade.setStateIfValidTransitionTo(Trade.State.BUYER_PUBLISHED_PAYOUT_TX); + // TODO (woodser): send PayoutTxPublishedMessage to seller } + + // mark address entries as available + processModel.getXmrWalletService().resetAddressEntriesForPendingTrade(trade.getId()); } else { log.info("We got the payout tx already set from BuyerSetupPayoutTxListener and do nothing here. trade ID={}", trade.getId()); } @@ -89,7 +92,6 @@ public class BuyerProcessPaymentReceivedMessage extends TradeTask { } processModel.getTradeManager().requestPersistence(); - complete(); } catch (Throwable t) { failed(t); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java index 334d6c3d5a..a8c3ec1664 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java @@ -62,7 +62,7 @@ public class BuyerSendPaymentSentMessage extends SendMailboxMessageTask { trade.getCounterCurrencyTxId(), trade.getCounterCurrencyExtraData(), deterministicId, - trade.getBuyer().getPayoutTxHex(), + trade.getPayoutTxHex(), trade.getBuyer().getUpdatedMultisigHex(), trade.getSelf().getPaymentAccountKey() ); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPayoutTxPublishedMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPayoutTxPublishedMessage.java index 843124d947..bef3626b90 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPayoutTxPublishedMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSendPayoutTxPublishedMessage.java @@ -50,13 +50,13 @@ public class BuyerSendPayoutTxPublishedMessage extends SendMailboxMessageTask { @Override protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) { - checkNotNull(trade.getSelf().getPayoutTxHex(), "Payout tx must not be null"); + checkNotNull(trade.getPayoutTxHex(), "Payout tx must not be null"); return new PayoutTxPublishedMessage( tradeId, processModel.getMyNodeAddress(), trade.isMaker(), null, // TODO: send witness data? - trade.getSelf().getPayoutTxHex() + trade.getPayoutTxHex() ); } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSetupPayoutTxListener.java b/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSetupPayoutTxListener.java deleted file mode 100644 index a122455551..0000000000 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/BuyerSetupPayoutTxListener.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see . - */ - -package bisq.core.trade.protocol.tasks; - -import bisq.core.trade.Trade; -import bisq.common.taskrunner.TaskRunner; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class BuyerSetupPayoutTxListener extends SetupPayoutTxListener { - public BuyerSetupPayoutTxListener(TaskRunner taskHandler, Trade trade) { - super(taskHandler, trade); - } - - @Override - protected void run() { - try { - runInterceptHook(); - - super.run(); - - } catch (Throwable t) { - failed(t); - } - } - - @Override - protected void setState() { - trade.setStateIfValidTransitionTo(Trade.State.BUYER_SAW_PAYOUT_TX_IN_NETWORK); - - processModel.getTradeManager().requestPersistence(); - } -} diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerMaybeSendPayoutTxPublishedMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerMaybeSendPayoutTxPublishedMessage.java index 905b6b5492..215144df70 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerMaybeSendPayoutTxPublishedMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerMaybeSendPayoutTxPublishedMessage.java @@ -65,13 +65,13 @@ public class SellerMaybeSendPayoutTxPublishedMessage extends SendMailboxMessageT @Override protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) { - checkNotNull(trade.getSelf().getPayoutTxHex(), "Payout tx must not be null"); + checkNotNull(trade.getPayoutTxHex(), "Payout tx must not be null"); return new PayoutTxPublishedMessage( tradeId, processModel.getMyNodeAddress(), trade.isMaker(), null, // TODO: send witness data? - trade.getSelf().getPayoutTxHex() + trade.getPayoutTxHex() ); } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java index 6816845f12..7fc18cdfaa 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java @@ -38,17 +38,21 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask { runInterceptHook(); // verify, sign, and publish payout tx if given. otherwise create payout tx - if (trade.getBuyer().getPayoutTxHex() != null) { + if (trade.getPayoutTxHex() != null) { log.info("Seller verifying, signing, and publishing payout tx"); - trade.verifyPayoutTx(trade.getBuyer().getPayoutTxHex(), true, true); + trade.verifyPayoutTx(trade.getPayoutTxHex(), true, true); } else { + + // create unsigned payout tx log.info("Seller creating unsigned payout tx"); MoneroTxWallet payoutTx = trade.createPayoutTx(); System.out.println("created payout tx: " + payoutTx); - trade.getSeller().setPayoutTx(payoutTx); - trade.getSeller().setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); - } + trade.setPayoutTx(payoutTx); + trade.setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + // start listening for published payout tx + trade.listenForPayoutTx(); + } complete(); } catch (Throwable t) { failed(t); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerProcessPaymentSentMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerProcessPaymentSentMessage.java index e576fcf659..2db1e918b6 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerProcessPaymentSentMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerProcessPaymentSentMessage.java @@ -43,7 +43,7 @@ public class SellerProcessPaymentSentMessage extends TradeTask { checkNotNull(message); // store buyer info - trade.getBuyer().setPayoutTxHex(message.getPayoutTxHex()); + trade.setPayoutTxHex(message.getPayoutTxHex()); trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex()); // decrypt buyer's payment account payload diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java index 8c610ad987..08f5d86dec 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java @@ -42,7 +42,7 @@ public class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask { try { runInterceptHook(); - if (trade.getSeller().getPayoutTxHex() == null) { + if (trade.getPayoutTxHex() == null) { log.error("Payout tx is null"); failed("Payout tx is null"); return; @@ -56,12 +56,12 @@ public class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask { @Override protected TradeMailboxMessage getTradeMailboxMessage(String id) { - checkNotNull(trade.getSeller().getPayoutTxHex(), "Payout tx must not be null"); + checkNotNull(trade.getPayoutTxHex(), "Payout tx must not be null"); return new PaymentReceivedMessage( id, processModel.getMyNodeAddress(), signedWitness, - trade.getSeller().getPayoutTxHex() + trade.getPayoutTxHex() ); } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/SetupPayoutTxListener.java b/core/src/main/java/bisq/core/trade/protocol/tasks/SetupPayoutTxListener.java index 4fb078633d..24056e560c 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/SetupPayoutTxListener.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/SetupPayoutTxListener.java @@ -17,120 +17,50 @@ package bisq.core.trade.protocol.tasks; -import bisq.core.btc.listeners.AddressConfidenceListener; -import bisq.core.btc.wallet.XmrWalletService; -import bisq.core.trade.Trade; - import bisq.common.UserThread; import bisq.common.taskrunner.TaskRunner; - -import org.bitcoinj.core.TransactionConfidence; - +import bisq.core.trade.Trade; +import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import java.util.List; - -import lombok.extern.slf4j.Slf4j; - - - -import monero.wallet.model.MoneroTransferQuery; -import monero.wallet.model.MoneroTxQuery; -import monero.wallet.model.MoneroTxWallet; - @Slf4j -public abstract class SetupPayoutTxListener extends TradeTask { - // Use instance fields to not get eaten up by the GC - private Subscription tradeStateSubscription; - private AddressConfidenceListener confidenceListener; +public class SetupPayoutTxListener extends TradeTask { - public SetupPayoutTxListener(TaskRunner taskHandler, Trade trade) { + private Subscription tradeStateSubscription; + + @SuppressWarnings({ "unused" }) + public SetupPayoutTxListener(TaskRunner taskHandler, Trade trade) { super(taskHandler, trade); } - - protected abstract void setState(); - @Override protected void run() { try { runInterceptHook(); - System.out.println("NEED TO IMPLEMENT PAYOUT TX LISTENER!"); // TODO (woodser): implement SetupPayoutTxListener -// if (!trade.isPayoutPublished()) { -// BtcWalletService walletService = processModel.getBtcWalletService(); -// String id = processModel.getOffer().getId(); -// Address address = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.TRADE_PAYOUT).getAddress(); -// -// TransactionConfidence confidence = walletService.getConfidenceForAddress(address); -// if (isInNetwork(confidence)) { -// applyConfidence(confidence); -// } else { -// confidenceListener = new AddressConfidenceListener(address) { -// @Override -// public void onTransactionConfidenceChanged(TransactionConfidence confidence) { -// if (isInNetwork(confidence)) -// applyConfidence(confidence); -// } -// }; -// walletService.addAddressConfidenceListener(confidenceListener); -// -// tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> { -// if (trade.isPayoutPublished()) { -// processModel.getBtcWalletService().resetCoinLockedInMultiSigAddressEntry(trade.getId()); -// -// // hack to remove tradeStateSubscription at callback -// UserThread.execute(this::unSubscribe); -// } -// }); -// } -// } - // we complete immediately, our object stays alive because the balanceListener is stored in the WalletService + // skip if payout already published + if (!trade.isPayoutPublished()) { + + // listen for payout tx + trade.listenForPayoutTx(); + tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> { + if (trade.isPayoutPublished()) { + + // cleanup on trade completion + processModel.getXmrWalletService().resetAddressEntriesForPendingTrade(trade.getId()); + UserThread.execute(this::unSubscribe); // unsubscribe + } + }); + } + complete(); } catch (Throwable t) { failed(t); } } - private void applyPayoutTx(int accountIdx) { - if (trade.getPayoutTx() == null) { - - // get txs with transfers to payout subaddress - List txs = processModel.getProvider().getXmrWalletService().getWallet().getTxs(new MoneroTxQuery() - .setTransferQuery(new MoneroTransferQuery().setAccountIndex(accountIdx).setSubaddressIndex(0).setIsIncoming(true))); // TODO (woodser): hardcode account 0 as savings wallet, subaddress 0 trade accounts in config - - // resolve payout tx if multiple txs sent to payout address - MoneroTxWallet payoutTx; - if (txs.size() > 1) { - throw new RuntimeException("Need to resolve multiple payout txs"); // TODO (woodser) - } else { - payoutTx = txs.get(0); - } - - trade.setPayoutTx(payoutTx); - XmrWalletService.printTxs("payoutTx received from network", payoutTx); - setState(); - } else { - log.info("We had the payout tx already set. tradeId={}, state={}", trade.getId(), trade.getState()); - } - - processModel.getBtcWalletService().resetCoinLockedInMultiSigAddressEntry(trade.getId()); - - // need delay as it can be called inside the handler before the listener and tradeStateSubscription are actually set. - UserThread.execute(this::unSubscribe); - } - - private boolean isInNetwork(TransactionConfidence confidence) { - return confidence != null && - (confidence.getConfidenceType().equals(TransactionConfidence.ConfidenceType.BUILDING) || - confidence.getConfidenceType().equals(TransactionConfidence.ConfidenceType.PENDING)); - } - private void unSubscribe() { - if (tradeStateSubscription != null) - tradeStateSubscription.unsubscribe(); - - if (confidenceListener != null) - processModel.getBtcWalletService().removeAddressConfidenceListener(confidenceListener); + if (tradeStateSubscription != null) tradeStateSubscription.unsubscribe(); } } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java b/core/src/main/java/bisq/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java index 085fe2fe94..28da0c1694 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java @@ -17,17 +17,16 @@ package bisq.core.trade.protocol.tasks.mediation; -import bisq.core.support.dispute.mediation.MediationResultState; -import bisq.core.trade.Trade; -import bisq.core.trade.protocol.tasks.SetupPayoutTxListener; - import bisq.common.taskrunner.TaskRunner; - +import bisq.core.trade.Trade; +import bisq.core.trade.protocol.tasks.TradeTask; import lombok.extern.slf4j.Slf4j; @Slf4j -public class SetupMediatedPayoutTxListener extends SetupPayoutTxListener { - public SetupMediatedPayoutTxListener(TaskRunner taskHandler, Trade trade) { +public class SetupMediatedPayoutTxListener extends TradeTask { + + @SuppressWarnings({ "unused" }) + public SetupMediatedPayoutTxListener(TaskRunner taskHandler, Trade trade) { super(taskHandler, trade); } @@ -35,20 +34,10 @@ public class SetupMediatedPayoutTxListener extends SetupPayoutTxListener { protected void run() { try { runInterceptHook(); - - super.run(); - + if (true) throw new RuntimeException("Not implemented"); + complete(); } catch (Throwable t) { failed(t); } } - - @Override - protected void setState() { - trade.setMediationResultState(MediationResultState.PAYOUT_TX_SEEN_IN_NETWORK); - if (trade.getPayoutTx() != null) { - processModel.getTradeManager().closeDisputedTrade(trade.getId(), Trade.DisputeState.MEDIATION_CLOSED); - } - processModel.getTradeManager().requestPersistence(); - } } diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java index 7da9e6ddc1..93991c72ec 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java @@ -176,11 +176,12 @@ class GrpcTradesService extends TradesImplBase { } } + // TODO: rename KeepFundsRequest to CloseTradeRequest @Override public void keepFunds(KeepFundsRequest req, StreamObserver responseObserver) { try { - coreApi.keepFunds(req.getTradeId()); + coreApi.closeTrade(req.getTradeId()); var reply = KeepFundsReply.newBuilder().build(); responseObserver.onNext(reply); responseObserver.onCompleted(); diff --git a/desktop/src/main/java/bisq/desktop/main/debug/DebugView.java b/desktop/src/main/java/bisq/desktop/main/debug/DebugView.java index 042a4c77c6..76f7171255 100644 --- a/desktop/src/main/java/bisq/desktop/main/debug/DebugView.java +++ b/desktop/src/main/java/bisq/desktop/main/debug/DebugView.java @@ -30,7 +30,6 @@ import bisq.core.trade.protocol.tasks.ApplyFilter; import bisq.core.trade.protocol.tasks.BuyerPreparePaymentSentMessage; import bisq.core.trade.protocol.tasks.BuyerProcessPaymentReceivedMessage; import bisq.core.trade.protocol.tasks.BuyerSendPaymentSentMessage; -import bisq.core.trade.protocol.tasks.BuyerSetupPayoutTxListener; import bisq.core.trade.protocol.tasks.MakerSetLockTime; import bisq.core.trade.protocol.tasks.MakerRemoveOpenOffer; import bisq.core.trade.protocol.tasks.SellerPreparePaymentReceivedMessage; @@ -38,6 +37,7 @@ import bisq.core.trade.protocol.tasks.SellerProcessPaymentSentMessage; import bisq.core.trade.protocol.tasks.SellerPublishDepositTx; import bisq.core.trade.protocol.tasks.SellerPublishTradeStatistics; import bisq.core.trade.protocol.tasks.SellerSendPaymentReceivedMessage; +import bisq.core.trade.protocol.tasks.SetupPayoutTxListener; import bisq.core.trade.protocol.tasks.TakerVerifyMakerFeePayment; import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness; import bisq.common.taskrunner.Task; @@ -123,7 +123,7 @@ public class DebugView extends InitializableView { ApplyFilter.class, BuyerPreparePaymentSentMessage.class, - BuyerSetupPayoutTxListener.class, + SetupPayoutTxListener.class, BuyerSendPaymentSentMessage.class, BuyerProcessPaymentReceivedMessage.class @@ -142,7 +142,7 @@ public class DebugView extends InitializableView { ApplyFilter.class, TakerVerifyMakerFeePayment.class, BuyerPreparePaymentSentMessage.class, - BuyerSetupPayoutTxListener.class, + SetupPayoutTxListener.class, BuyerSendPaymentSentMessage.class, BuyerProcessPaymentReceivedMessage.class) diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java index b9a10220ec..9d0c63923b 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java @@ -200,7 +200,7 @@ public class TradeDetailsWindow extends Overlay { trade.getAssetTxProofResult() != null && trade.getAssetTxProofResult() != AssetTxProofResult.UNDEFINED; - if (trade.getPayoutTx() != null) + if (trade.getPayoutTxId() != null) rows++; boolean showDisputedTx = arbitrationManager.findOwnDispute(trade.getId()).isPresent() && arbitrationManager.findOwnDispute(trade.getId()).get().getDisputePayoutTxId() != null; @@ -283,9 +283,9 @@ public class TradeDetailsWindow extends Overlay { addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.depositTransactionId"), // TODO (woodser): separate UI labels for deposit tx ids trade.getTakerDepositTx().getHash()); - if (trade.getPayoutTx() != null) + if (trade.getPayoutTxId() != null) addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.payoutTxId"), - trade.getPayoutTx().getHash()); + trade.getPayoutTxId()); if (showDisputedTx) addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("tradeDetailsWindow.disputedPayoutTxId"), arbitrationManager.findOwnDispute(trade.getId()).get().getDisputePayoutTxId()); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java index 03ce2eafc7..4ded5304ec 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -91,7 +91,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import monero.daemon.model.MoneroTx; import monero.wallet.MoneroWallet; -import monero.wallet.model.MoneroTxWallet; public class PendingTradesDataModel extends ActivatableDataModel { @Getter @@ -465,11 +464,10 @@ public class PendingTradesDataModel extends ActivatableDataModel { byte[] payoutTxSerialized = null; String payoutTxHashAsString = null; - MoneroTxWallet payoutTx = trade.getPayoutTx(); MoneroWallet multisigWallet = xmrWalletService.getMultisigWallet(trade.getId()); String updatedMultisigHex = multisigWallet.exportMultisigHex(); xmrWalletService.closeMultisigWallet(trade.getId()); // close multisig wallet - if (payoutTx != null) { + if (trade.getPayoutTxId() != null) { // payoutTxSerialized = payoutTx.bitcoinSerialize(); // TODO (woodser): no need to pass serialized txs for xmr // payoutTxHashAsString = payoutTx.getHashAsString(); } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java index 503844f4ea..0af842bb49 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -420,7 +420,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel