diff --git a/common/src/main/java/bisq/common/app/Version.java b/common/src/main/java/bisq/common/app/Version.java index 24f61ed2b83..a7b810cb939 100644 --- a/common/src/main/java/bisq/common/app/Version.java +++ b/common/src/main/java/bisq/common/app/Version.java @@ -17,9 +17,13 @@ package bisq.common.app; +import bisq.common.util.Utilities; + import java.net.URL; import java.util.Arrays; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -107,7 +111,18 @@ private static int getSubVersion(String version, int index) { // Version 1.2.2 -> TRADE_PROTOCOL_VERSION = 2 // Version 1.5.0 -> TRADE_PROTOCOL_VERSION = 3 // Version 1.7.0 -> TRADE_PROTOCOL_VERSION = 4 - public static final int TRADE_PROTOCOL_VERSION = 4; + // Version 1.9.13 and after activation date -> TRADE_PROTOCOL_VERSION = 5 + + public static final Date PROTOCOL_5_ACTIVATION_DATE = Utilities.getUTCDate(2023, GregorianCalendar.OCTOBER, 1); + + public static boolean isTradeProtocolVersion5Activated() { + return new Date().after(PROTOCOL_5_ACTIVATION_DATE); + } + + public static int getTradeProtocolVersion() { + return isTradeProtocolVersion5Activated() ? 5 : 4; + } + private static int p2pMessageVersion; public static final String BSQ_TX_VERSION = "1"; @@ -136,7 +151,7 @@ public static void printVersion() { "VERSION=" + VERSION + ", P2P_NETWORK_VERSION=" + P2P_NETWORK_VERSION + ", LOCAL_DB_VERSION=" + LOCAL_DB_VERSION + - ", TRADE_PROTOCOL_VERSION=" + TRADE_PROTOCOL_VERSION + + ", TRADE_PROTOCOL_VERSION=" + getTradeProtocolVersion() + ", BASE_CURRENCY_NETWORK=" + BASE_CURRENCY_NETWORK + ", getP2PNetworkId()=" + getP2PMessageVersion() + '}'); diff --git a/core/src/main/java/bisq/core/api/CoreTradesService.java b/core/src/main/java/bisq/core/api/CoreTradesService.java index 17f10803565..1b3949e2102 100644 --- a/core/src/main/java/bisq/core/api/CoreTradesService.java +++ b/core/src/main/java/bisq/core/api/CoreTradesService.java @@ -38,8 +38,8 @@ import bisq.core.trade.model.TradeModel; import bisq.core.trade.model.bisq_v1.Trade; import bisq.core.trade.model.bsq_swap.BsqSwapTrade; -import bisq.core.trade.protocol.bisq_v1.BuyerProtocol; -import bisq.core.trade.protocol.bisq_v1.SellerProtocol; +import bisq.core.trade.protocol.BuyerProtocol; +import bisq.core.trade.protocol.SellerProtocol; import bisq.core.user.User; import bisq.core.util.validation.BtcAddressValidator; diff --git a/core/src/main/java/bisq/core/offer/OfferFilterService.java b/core/src/main/java/bisq/core/offer/OfferFilterService.java index 11a8877fe62..7f7cfb8017a 100644 --- a/core/src/main/java/bisq/core/offer/OfferFilterService.java +++ b/core/src/main/java/bisq/core/offer/OfferFilterService.java @@ -138,7 +138,7 @@ public boolean isAnyPaymentAccountValidForOffer(Offer offer) { } public boolean hasSameProtocolVersion(Offer offer) { - return offer.getProtocolVersion() == Version.TRADE_PROTOCOL_VERSION; + return offer.getProtocolVersion() == Version.getTradeProtocolVersion(); } public boolean isIgnored(Offer offer) { diff --git a/core/src/main/java/bisq/core/offer/OpenOfferManager.java b/core/src/main/java/bisq/core/offer/OpenOfferManager.java index 7ea84ff0b3b..0799e9b4ff9 100644 --- a/core/src/main/java/bisq/core/offer/OpenOfferManager.java +++ b/core/src/main/java/bisq/core/offer/OpenOfferManager.java @@ -934,7 +934,7 @@ private void maybeUpdatePersistedOffers() { // Capability.REFUND_AGENT in v1.2.0 and want to rewrite a // persisted offer after the user has updated to 1.2.0 so their offer will be accepted by the network. - if (original.getProtocolVersion() < Version.TRADE_PROTOCOL_VERSION || + if (original.getProtocolVersion() < Version.getTradeProtocolVersion() || !OfferRestrictions.hasOfferMandatoryCapability(originalOffer, Capability.MEDIATION) || !OfferRestrictions.hasOfferMandatoryCapability(originalOffer, Capability.REFUND_AGENT) || !original.getOwnerNodeAddress().equals(p2PService.getAddress())) { @@ -960,9 +960,9 @@ private void maybeUpdatePersistedOffers() { // - Protocol version changed? int protocolVersion = original.getProtocolVersion(); - if (protocolVersion < Version.TRADE_PROTOCOL_VERSION) { + if (protocolVersion < Version.getTradeProtocolVersion()) { // We update the trade protocol version - protocolVersion = Version.TRADE_PROTOCOL_VERSION; + protocolVersion = Version.getTradeProtocolVersion(); log.info("Updated the protocol version of offer id={}", originalOffer.getId()); } diff --git a/core/src/main/java/bisq/core/offer/bisq_v1/CreateOfferService.java b/core/src/main/java/bisq/core/offer/bisq_v1/CreateOfferService.java index f984dd9ddff..c9bb0467f7f 100644 --- a/core/src/main/java/bisq/core/offer/bisq_v1/CreateOfferService.java +++ b/core/src/main/java/bisq/core/offer/bisq_v1/CreateOfferService.java @@ -216,7 +216,7 @@ public Offer createAndGetOffer(String offerId, isPrivateOffer, hashOfChallenge, extraDataMap, - Version.TRADE_PROTOCOL_VERSION); + Version.getTradeProtocolVersion()); Offer offer = new Offer(offerPayload); offer.setPriceFeedService(priceFeedService); return offer; diff --git a/core/src/main/java/bisq/core/offer/bsq_swap/OpenBsqSwapOfferService.java b/core/src/main/java/bisq/core/offer/bsq_swap/OpenBsqSwapOfferService.java index 70735a57064..cd41276bddc 100644 --- a/core/src/main/java/bisq/core/offer/bsq_swap/OpenBsqSwapOfferService.java +++ b/core/src/main/java/bisq/core/offer/bsq_swap/OpenBsqSwapOfferService.java @@ -220,7 +220,7 @@ public void requestNewOffer(String offerId, proofOfWork, null, Version.VERSION, - Version.TRADE_PROTOCOL_VERSION); + Version.getTradeProtocolVersion()); resultHandler.accept(new Offer(bsqSwapOfferPayload)); }); }); diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 507e1934e88..1af3398b8a7 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -52,11 +52,11 @@ import bisq.core.trade.model.bsq_swap.BsqSwapSellerAsMakerTrade; import bisq.core.trade.model.bsq_swap.BsqSwapSellerAsTakerTrade; import bisq.core.trade.model.bsq_swap.BsqSwapTrade; +import bisq.core.trade.protocol.MakerProtocol; import bisq.core.trade.protocol.Provider; +import bisq.core.trade.protocol.TakerProtocol; import bisq.core.trade.protocol.TradeProtocol; import bisq.core.trade.protocol.TradeProtocolFactory; -import bisq.core.trade.protocol.bisq_v1.MakerProtocol; -import bisq.core.trade.protocol.bisq_v1.TakerProtocol; import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxRequest; import bisq.core.trade.protocol.bisq_v1.model.ProcessModel; import bisq.core.trade.protocol.bsq_swap.BsqSwapMakerProtocol; diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java new file mode 100644 index 00000000000..c7f474e973e --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java @@ -0,0 +1,25 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +public interface BuyerProtocol { + void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler); +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/MakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/MakerProtocol.java similarity index 96% rename from core/src/main/java/bisq/core/trade/protocol/bisq_v1/MakerProtocol.java rename to core/src/main/java/bisq/core/trade/protocol/MakerProtocol.java index 7c1b3299d77..204244a7eb9 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/MakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/MakerProtocol.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.core.trade.protocol.bisq_v1; +package bisq.core.trade.protocol; import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxRequest; diff --git a/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java new file mode 100644 index 00000000000..c5064f9b9ca --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java @@ -0,0 +1,26 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +public interface SellerProtocol { + + void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler); +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/TakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/TakerProtocol.java similarity index 90% rename from core/src/main/java/bisq/core/trade/protocol/bisq_v1/TakerProtocol.java rename to core/src/main/java/bisq/core/trade/protocol/TakerProtocol.java index b02b7cba91d..249d0ac73bd 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/TakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/TakerProtocol.java @@ -15,9 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.core.trade.protocol.bisq_v1; - -import bisq.core.trade.protocol.FluentProtocol; +package bisq.core.trade.protocol; public interface TakerProtocol { void onTakeOffer(); diff --git a/core/src/main/java/bisq/core/trade/protocol/TradeProtocolFactory.java b/core/src/main/java/bisq/core/trade/protocol/TradeProtocolFactory.java index 54549adc2f0..6eb8ae441a5 100644 --- a/core/src/main/java/bisq/core/trade/protocol/TradeProtocolFactory.java +++ b/core/src/main/java/bisq/core/trade/protocol/TradeProtocolFactory.java @@ -26,34 +26,55 @@ import bisq.core.trade.model.bsq_swap.BsqSwapBuyerAsTakerTrade; import bisq.core.trade.model.bsq_swap.BsqSwapSellerAsMakerTrade; import bisq.core.trade.model.bsq_swap.BsqSwapSellerAsTakerTrade; +import bisq.core.trade.model.bsq_swap.BsqSwapTrade; import bisq.core.trade.protocol.bisq_v1.BuyerAsMakerProtocol; import bisq.core.trade.protocol.bisq_v1.BuyerAsTakerProtocol; import bisq.core.trade.protocol.bisq_v1.SellerAsMakerProtocol; import bisq.core.trade.protocol.bisq_v1.SellerAsTakerProtocol; +import bisq.core.trade.protocol.bisq_v5.BuyerAsMakerProtocol_v5; +import bisq.core.trade.protocol.bisq_v5.BuyerAsTakerProtocol_v5; +import bisq.core.trade.protocol.bisq_v5.SellerAsMakerProtocol_v5; +import bisq.core.trade.protocol.bisq_v5.SellerAsTakerProtocol_v5; import bisq.core.trade.protocol.bsq_swap.BsqSwapBuyerAsMakerProtocol; import bisq.core.trade.protocol.bsq_swap.BsqSwapBuyerAsTakerProtocol; import bisq.core.trade.protocol.bsq_swap.BsqSwapSellerAsMakerProtocol; import bisq.core.trade.protocol.bsq_swap.BsqSwapSellerAsTakerProtocol; +import bisq.common.app.Version; + public class TradeProtocolFactory { public static TradeProtocol getNewTradeProtocol(TradeModel tradeModel) { + if (tradeModel instanceof BsqSwapTrade) { + if (tradeModel instanceof BsqSwapBuyerAsMakerTrade) { + return new BsqSwapBuyerAsMakerProtocol((BsqSwapBuyerAsMakerTrade) tradeModel); + } else if (tradeModel instanceof BsqSwapBuyerAsTakerTrade) { + return new BsqSwapBuyerAsTakerProtocol((BsqSwapBuyerAsTakerTrade) tradeModel); + } else if (tradeModel instanceof BsqSwapSellerAsMakerTrade) { + return new BsqSwapSellerAsMakerProtocol((BsqSwapSellerAsMakerTrade) tradeModel); + } else if (tradeModel instanceof BsqSwapSellerAsTakerTrade) { + return new BsqSwapSellerAsTakerProtocol((BsqSwapSellerAsTakerTrade) tradeModel); + } + } + + boolean tradeProtocolVersion5Activated = Version.isTradeProtocolVersion5Activated(); if (tradeModel instanceof BuyerAsMakerTrade) { - return new BuyerAsMakerProtocol((BuyerAsMakerTrade) tradeModel); + return tradeProtocolVersion5Activated ? + new BuyerAsMakerProtocol_v5((BuyerAsMakerTrade) tradeModel) : + new BuyerAsMakerProtocol((BuyerAsMakerTrade) tradeModel); } else if (tradeModel instanceof BuyerAsTakerTrade) { - return new BuyerAsTakerProtocol((BuyerAsTakerTrade) tradeModel); + return tradeProtocolVersion5Activated ? + new BuyerAsTakerProtocol_v5((BuyerAsTakerTrade) tradeModel) : + new BuyerAsTakerProtocol((BuyerAsTakerTrade) tradeModel); } else if (tradeModel instanceof SellerAsMakerTrade) { - return new SellerAsMakerProtocol((SellerAsMakerTrade) tradeModel); + return tradeProtocolVersion5Activated ? + new SellerAsMakerProtocol_v5((SellerAsMakerTrade) tradeModel) : + new SellerAsMakerProtocol((SellerAsMakerTrade) tradeModel); } else if (tradeModel instanceof SellerAsTakerTrade) { - return new SellerAsTakerProtocol((SellerAsTakerTrade) tradeModel); - } else if (tradeModel instanceof BsqSwapBuyerAsMakerTrade) { - return new BsqSwapBuyerAsMakerProtocol((BsqSwapBuyerAsMakerTrade) tradeModel); - } else if (tradeModel instanceof BsqSwapBuyerAsTakerTrade) { - return new BsqSwapBuyerAsTakerProtocol((BsqSwapBuyerAsTakerTrade) tradeModel); - } else if (tradeModel instanceof BsqSwapSellerAsMakerTrade) { - return new BsqSwapSellerAsMakerProtocol((BsqSwapSellerAsMakerTrade) tradeModel); - } else if (tradeModel instanceof BsqSwapSellerAsTakerTrade) { - return new BsqSwapSellerAsTakerProtocol((BsqSwapSellerAsTakerTrade) tradeModel); - } else - throw new IllegalStateException("Trade not of expected type. Trade=" + tradeModel); + return tradeProtocolVersion5Activated ? + new SellerAsTakerProtocol_v5((SellerAsTakerTrade) tradeModel) : + new SellerAsTakerProtocol((SellerAsTakerTrade) tradeModel); + } + + throw new IllegalStateException("Trade not of expected type. Trade=" + tradeModel); } } diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BaseBuyerProtocol.java similarity index 98% rename from core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerProtocol.java rename to core/src/main/java/bisq/core/trade/protocol/bisq_v1/BaseBuyerProtocol.java index 858cada6c85..27a0deadd02 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BaseBuyerProtocol.java @@ -19,6 +19,7 @@ import bisq.core.trade.model.bisq_v1.BuyerTrade; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.BuyerProtocol; import bisq.core.trade.protocol.FluentProtocol; import bisq.core.trade.protocol.TradeMessage; import bisq.core.trade.protocol.TradeTaskRunner; @@ -45,7 +46,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -public abstract class BuyerProtocol extends DisputeProtocol { +abstract class BaseBuyerProtocol extends DisputeProtocol implements BuyerProtocol { enum BuyerEvent implements FluentProtocol.Event { STARTUP, PAYMENT_SENT @@ -55,7 +56,7 @@ enum BuyerEvent implements FluentProtocol.Event { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public BuyerProtocol(BuyerTrade trade) { + protected BaseBuyerProtocol(BuyerTrade trade) { super(trade); } diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BaseSellerProtocol.java similarity index 97% rename from core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerProtocol.java rename to core/src/main/java/bisq/core/trade/protocol/bisq_v1/BaseSellerProtocol.java index 46a4a74fd15..a4c1270562d 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BaseSellerProtocol.java @@ -20,6 +20,7 @@ import bisq.core.trade.model.bisq_v1.SellerTrade; import bisq.core.trade.model.bisq_v1.Trade; import bisq.core.trade.protocol.FluentProtocol; +import bisq.core.trade.protocol.SellerProtocol; import bisq.core.trade.protocol.TradeMessage; import bisq.core.trade.protocol.TradeTaskRunner; import bisq.core.trade.protocol.bisq_v1.messages.CounterCurrencyTransferStartedMessage; @@ -47,13 +48,13 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -public abstract class SellerProtocol extends DisputeProtocol { +abstract class BaseSellerProtocol extends DisputeProtocol implements SellerProtocol { enum SellerEvent implements FluentProtocol.Event { STARTUP, PAYMENT_RECEIVED } - public SellerProtocol(SellerTrade trade) { + protected BaseSellerProtocol(SellerTrade trade) { super(trade); } diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsMakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsMakerProtocol.java index 83bda8ac8bf..10fad61fa74 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsMakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsMakerProtocol.java @@ -19,6 +19,7 @@ import bisq.core.trade.model.bisq_v1.BuyerAsMakerTrade; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.MakerProtocol; import bisq.core.trade.protocol.TradeTaskRunner; import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureRequest; import bisq.core.trade.protocol.bisq_v1.messages.DepositTxAndDelayedPayoutTxMessage; @@ -49,7 +50,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol { +public class BuyerAsMakerProtocol extends BaseBuyerProtocol implements MakerProtocol { /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -111,7 +112,6 @@ protected void handle(DelayedPayoutTxSignatureRequest message, NodeAddress peer) .executeTasks(); } - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(DepositTxAndDelayedPayoutTxMessage message, NodeAddress peer) { super.handle(message, peer); @@ -122,7 +122,6 @@ protected void handle(DepositTxAndDelayedPayoutTxMessage message, NodeAddress pe // User interaction /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which events we expect @Override public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { super.onPaymentStarted(resultHandler, errorMessageHandler); @@ -133,7 +132,6 @@ public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler er // Incoming message Payout tx /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(PayoutTxPublishedMessage message, NodeAddress peer) { super.handle(message, peer); diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsTakerProtocol.java index d7b9413db59..b67b60507af 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/BuyerAsTakerProtocol.java @@ -21,6 +21,7 @@ import bisq.core.offer.Offer; import bisq.core.trade.model.bisq_v1.BuyerAsTakerTrade; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.TakerProtocol; import bisq.core.trade.protocol.TradeMessage; import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureRequest; import bisq.core.trade.protocol.bisq_v1.messages.DepositTxAndDelayedPayoutTxMessage; @@ -55,7 +56,7 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j -public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol { +public class BuyerAsTakerProtocol extends BaseBuyerProtocol implements TakerProtocol { /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -126,7 +127,6 @@ protected void handle(DelayedPayoutTxSignatureRequest message, NodeAddress peer) .executeTasks(); } - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(DepositTxAndDelayedPayoutTxMessage message, NodeAddress peer) { super.handle(message, peer); @@ -137,7 +137,6 @@ protected void handle(DepositTxAndDelayedPayoutTxMessage message, NodeAddress pe // User interaction /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which events we expect @Override public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { super.onPaymentStarted(resultHandler, errorMessageHandler); @@ -148,7 +147,6 @@ public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler er // Incoming message Payout tx /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(PayoutTxPublishedMessage message, NodeAddress peer) { super.handle(message, peer); diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsMakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsMakerProtocol.java index c88e7de0f87..3494a0cb124 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsMakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsMakerProtocol.java @@ -20,12 +20,14 @@ import bisq.core.trade.model.bisq_v1.SellerAsMakerTrade; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.MakerProtocol; import bisq.core.trade.protocol.TradeMessage; import bisq.core.trade.protocol.TradeTaskRunner; import bisq.core.trade.protocol.bisq_v1.messages.CounterCurrencyTransferStartedMessage; import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureResponse; import bisq.core.trade.protocol.bisq_v1.messages.DepositTxMessage; import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxRequest; +import bisq.core.trade.protocol.bisq_v1.messages.ShareBuyerPaymentAccountMessage; import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; import bisq.core.trade.protocol.bisq_v1.tasks.CheckIfDaoStateIsInSync; import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; @@ -51,7 +53,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtocol { +public class SellerAsMakerProtocol extends BaseSellerProtocol implements MakerProtocol { /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -113,18 +115,21 @@ protected void handle(DepositTxMessage message, NodeAddress peer) { .executeTasks(); } - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(DelayedPayoutTxSignatureResponse message, NodeAddress peer) { super.handle(message, peer); } + @Override + protected void handle(ShareBuyerPaymentAccountMessage message, NodeAddress peer) { + super.handle(message, peer); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Incoming message when buyer has clicked payment started button /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(CounterCurrencyTransferStartedMessage message, NodeAddress peer) { super.handle(message, peer); @@ -135,7 +140,6 @@ protected void handle(CounterCurrencyTransferStartedMessage message, NodeAddress // User interaction /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which events we expect @Override public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { super.onPaymentReceived(resultHandler, errorMessageHandler); diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsTakerProtocol.java index 42804e7cd3d..84c37fe42ee 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerAsTakerProtocol.java @@ -21,10 +21,12 @@ import bisq.core.offer.Offer; import bisq.core.trade.model.bisq_v1.SellerAsTakerTrade; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.TakerProtocol; import bisq.core.trade.protocol.TradeMessage; import bisq.core.trade.protocol.bisq_v1.messages.CounterCurrencyTransferStartedMessage; import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureResponse; import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxResponse; +import bisq.core.trade.protocol.bisq_v1.messages.ShareBuyerPaymentAccountMessage; import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; import bisq.core.trade.protocol.bisq_v1.tasks.CheckIfDaoStateIsInSync; import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; @@ -51,7 +53,7 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j -public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtocol { +public class SellerAsTakerProtocol extends BaseSellerProtocol implements TakerProtocol { /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -107,18 +109,21 @@ private void handle(InputsForDepositTxResponse message, NodeAddress peer) { .executeTasks(); } - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(DelayedPayoutTxSignatureResponse message, NodeAddress peer) { super.handle(message, peer); } + @Override + protected void handle(ShareBuyerPaymentAccountMessage message, NodeAddress peer) { + super.handle(message, peer); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Incoming message when buyer has clicked payment started button /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which messages we expect @Override protected void handle(CounterCurrencyTransferStartedMessage message, NodeAddress peer) { super.handle(message, peer); @@ -129,7 +134,6 @@ protected void handle(CounterCurrencyTransferStartedMessage message, NodeAddress // User interaction /////////////////////////////////////////////////////////////////////////////////////////// - // We keep the handler here in as well to make it more transparent which events we expect @Override public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { super.onPaymentReceived(resultHandler, errorMessageHandler); diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BaseBuyerProtocol_v5.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BaseBuyerProtocol_v5.java new file mode 100644 index 00000000000..31ef8bc38cb --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BaseBuyerProtocol_v5.java @@ -0,0 +1,201 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol.bisq_v5; + +import bisq.core.trade.model.bisq_v1.BuyerTrade; +import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.BuyerProtocol; +import bisq.core.trade.protocol.FluentProtocol; +import bisq.core.trade.protocol.TradeMessage; +import bisq.core.trade.protocol.TradeTaskRunner; +import bisq.core.trade.protocol.bisq_v1.DisputeProtocol; +import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureRequest; +import bisq.core.trade.protocol.bisq_v1.messages.DepositTxAndDelayedPayoutTxMessage; +import bisq.core.trade.protocol.bisq_v1.messages.PayoutTxPublishedMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; +import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; +import bisq.core.trade.protocol.bisq_v1.tasks.VerifyPeersAccountAgeWitness; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerProcessDepositTxAndDelayedPayoutTxMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerProcessPayoutTxPublishedMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSendCounterCurrencyTransferStartedMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSendsShareBuyerPaymentAccountMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSetupDepositTxListener; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSetupPayoutTxListener; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSignPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerVerifiesFinalDelayedPayoutTx; + +import bisq.network.p2p.NodeAddress; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +abstract class BaseBuyerProtocol_v5 extends DisputeProtocol implements BuyerProtocol { + enum BuyerEvent implements FluentProtocol.Event { + STARTUP, + PAYMENT_SENT + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + protected BaseBuyerProtocol_v5(BuyerTrade trade) { + super(trade); + } + + @Override + protected void onInitialized() { + super.onInitialized(); + // We get called the constructor with any possible state and phase. As we don't want to log an error for such + // cases we use the alternative 'given' method instead of 'expect'. + given(phase(Trade.Phase.TAKER_FEE_PUBLISHED) + .with(BuyerEvent.STARTUP)) + .setup(tasks(BuyerSetupDepositTxListener.class)) + .executeTasks(); + + given(anyPhase(Trade.Phase.FIAT_SENT, Trade.Phase.FIAT_RECEIVED) + .with(BuyerEvent.STARTUP)) + .setup(tasks(BuyerSetupPayoutTxListener.class)) + .executeTasks(); + + given(anyPhase(Trade.Phase.FIAT_SENT, Trade.Phase.FIAT_RECEIVED) + .anyState(Trade.State.BUYER_STORED_IN_MAILBOX_FIAT_PAYMENT_INITIATED_MSG, + Trade.State.BUYER_SEND_FAILED_FIAT_PAYMENT_INITIATED_MSG) + .with(BuyerEvent.STARTUP)) + .setup(tasks(BuyerSendCounterCurrencyTransferStartedMessage.class)) + .executeTasks(); + } + + @Override + public void onMailboxMessage(TradeMessage message, NodeAddress peer) { + super.onMailboxMessage(message, peer); + + if (message instanceof DepositTxAndDelayedPayoutTxMessage) { + handle((DepositTxAndDelayedPayoutTxMessage) message, peer); + } else if (message instanceof PayoutTxPublishedMessage) { + handle((PayoutTxPublishedMessage) message, peer); + } + } + + protected abstract void handle(DelayedPayoutTxSignatureRequest message, NodeAddress peer); + + // The DepositTxAndDelayedPayoutTxMessage is a mailbox message. Earlier we used only the deposit tx which can + // be set also when received by the network once published by the peer so that message was not mandatory and could + // have arrived as mailbox message. + // Now we send the delayed payout tx as well and with that this message is mandatory for continuing the protocol. + // We do not support mailbox message handling during the take offer process as it is expected that both peers + // are online. + // For backward compatibility and extra resilience we still keep DepositTxAndDelayedPayoutTxMessage as a + // mailbox message but the stored in mailbox case is not expected and the seller would try to send the message again + // in the hope to reach the buyer directly in case of network issues. + protected void handle(DepositTxAndDelayedPayoutTxMessage message, NodeAddress peer) { + expect(anyPhase(Trade.Phase.TAKER_FEE_PUBLISHED, Trade.Phase.DEPOSIT_PUBLISHED) + .with(message) + .from(peer) + .preCondition(trade.getDepositTx() == null || processModel.getTradePeer().getPaymentAccountPayload() == null, + () -> { + log.warn("We received a DepositTxAndDelayedPayoutTxMessage but we have already processed the deposit and " + + "delayed payout tx so we ignore the message. This can happen if the ACK message to the peer did not " + + "arrive and the peer repeats sending us the message. We send another ACK msg."); + stopTimeout(); + sendAckMessage(message, true, null); + removeMailboxMessageAfterProcessing(message); + })) + .setup(tasks(BuyerProcessDepositTxAndDelayedPayoutTxMessage.class, + ApplyFilter.class, + VerifyPeersAccountAgeWitness.class, + BuyerSendsShareBuyerPaymentAccountMessage.class, + BuyerVerifiesFinalDelayedPayoutTx.class) + .using(new TradeTaskRunner(trade, + () -> { + stopTimeout(); + handleTaskRunnerSuccess(message); + }, + errorMessage -> handleTaskRunnerFault(message, errorMessage)))) + .executeTasks(); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // User interaction + /////////////////////////////////////////////////////////////////////////////////////////// + + public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + BuyerEvent event = BuyerEvent.PAYMENT_SENT; + expect(phase(Trade.Phase.DEPOSIT_CONFIRMED) + .with(event) + .preCondition(trade.confirmPermitted())) + .setup(tasks(ApplyFilter.class, + getVerifyPeersFeePaymentClass(), + BuyerSignPayoutTx.class, + BuyerSetupPayoutTxListener.class, + BuyerSendCounterCurrencyTransferStartedMessage.class) + .using(new TradeTaskRunner(trade, + () -> { + resultHandler.handleResult(); + handleTaskRunnerSuccess(event); + }, + (errorMessage) -> { + errorMessageHandler.handleErrorMessage(errorMessage); + handleTaskRunnerFault(event, errorMessage); + }))) + .run(() -> { + trade.setState(Trade.State.BUYER_CONFIRMED_IN_UI_FIAT_PAYMENT_INITIATED); + processModel.getTradeManager().requestPersistence(); + }) + .executeTasks(); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming message Payout tx + /////////////////////////////////////////////////////////////////////////////////////////// + + protected void handle(PayoutTxPublishedMessage message, NodeAddress peer) { + expect(anyPhase(Trade.Phase.FIAT_SENT, Trade.Phase.PAYOUT_PUBLISHED) + .with(message) + .from(peer)) + .setup(tasks(BuyerProcessPayoutTxPublishedMessage.class)) + .executeTasks(); + + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Message dispatcher + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void onTradeMessage(TradeMessage message, NodeAddress peer) { + super.onTradeMessage(message, peer); + + log.info("Received {} from {} with tradeId {} and uid {}", + message.getClass().getSimpleName(), peer, message.getTradeId(), message.getUid()); + + if (message instanceof DelayedPayoutTxSignatureRequest) { + handle((DelayedPayoutTxSignatureRequest) message, peer); + } else if (message instanceof DepositTxAndDelayedPayoutTxMessage) { + handle((DepositTxAndDelayedPayoutTxMessage) message, peer); + } else if (message instanceof PayoutTxPublishedMessage) { + handle((PayoutTxPublishedMessage) message, peer); + } + } + + abstract protected Class getVerifyPeersFeePaymentClass(); +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BaseSellerProtocol_v5.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BaseSellerProtocol_v5.java new file mode 100644 index 00000000000..a98fb29ec5a --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BaseSellerProtocol_v5.java @@ -0,0 +1,188 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol.bisq_v5; + +import bisq.core.trade.model.bisq_v1.SellerTrade; +import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.FluentProtocol; +import bisq.core.trade.protocol.SellerProtocol; +import bisq.core.trade.protocol.TradeMessage; +import bisq.core.trade.protocol.TradeTaskRunner; +import bisq.core.trade.protocol.bisq_v1.DisputeProtocol; +import bisq.core.trade.protocol.bisq_v1.messages.CounterCurrencyTransferStartedMessage; +import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureResponse; +import bisq.core.trade.protocol.bisq_v1.messages.ShareBuyerPaymentAccountMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; +import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; +import bisq.core.trade.protocol.bisq_v1.tasks.VerifyPeersAccountAgeWitness; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerBroadcastPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerFinalizesDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerProcessCounterCurrencyTransferStartedMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerProcessDelayedPayoutTxSignatureResponse; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerProcessShareBuyerPaymentAccountMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerPublishesDepositTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerPublishesTradeStatistics; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerSendPayoutTxPublishedMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerSendsDepositTxAndDelayedPayoutTxMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerSignAndFinalizePayoutTx; + +import bisq.network.p2p.NodeAddress; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +abstract class BaseSellerProtocol_v5 extends DisputeProtocol implements SellerProtocol { + enum SellerEvent implements FluentProtocol.Event { + STARTUP, + PAYMENT_RECEIVED + } + + protected BaseSellerProtocol_v5(SellerTrade trade) { + super(trade); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Mailbox + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) { + super.onMailboxMessage(message, peerNodeAddress); + + if (message instanceof CounterCurrencyTransferStartedMessage) { + handle((CounterCurrencyTransferStartedMessage) message, peerNodeAddress); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming messages + /////////////////////////////////////////////////////////////////////////////////////////// + + protected void handle(DelayedPayoutTxSignatureResponse message, NodeAddress peer) { + expect(phase(Trade.Phase.TAKER_FEE_PUBLISHED) + .with(message) + .from(peer)) + .setup(tasks(SellerProcessDelayedPayoutTxSignatureResponse.class, + SellerFinalizesDelayedPayoutTx.class, + SellerSendsDepositTxAndDelayedPayoutTxMessage.class, + SellerPublishesDepositTx.class, + SellerPublishesTradeStatistics.class)) + .executeTasks(); + } + + protected void handle(ShareBuyerPaymentAccountMessage message, NodeAddress peer) { + expect(anyPhase(Trade.Phase.TAKER_FEE_PUBLISHED, Trade.Phase.DEPOSIT_PUBLISHED, Trade.Phase.DEPOSIT_CONFIRMED) + .with(message) + .from(peer)) + .setup(tasks(SellerProcessShareBuyerPaymentAccountMessage.class, + ApplyFilter.class, + VerifyPeersAccountAgeWitness.class)) + .run(() -> { + // We stop timeout here and don't start a new one as the + // SellerSendsDepositTxAndDelayedPayoutTxMessage repeats to send the message and has it's own + // timeout if it never succeeds. + stopTimeout(); + }) + .executeTasks(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming message when buyer has clicked payment started button + /////////////////////////////////////////////////////////////////////////////////////////// + + protected void handle(CounterCurrencyTransferStartedMessage message, NodeAddress peer) { + // We are more tolerant with expected phase and allow also DEPOSIT_PUBLISHED as it can be the case + // that the wallet is still syncing and so the DEPOSIT_CONFIRMED state to yet triggered when we received + // a mailbox message with CounterCurrencyTransferStartedMessage. + // TODO A better fix would be to add a listener for the wallet sync state and process + // the mailbox msg once wallet is ready and trade state set. + expect(anyPhase(Trade.Phase.DEPOSIT_CONFIRMED, Trade.Phase.DEPOSIT_PUBLISHED) + .with(message) + .from(peer) + .preCondition(trade.getPayoutTx() == null, + () -> { + log.warn("We received a CounterCurrencyTransferStartedMessage but we have already created the payout tx " + + "so we ignore the message. This can happen if the ACK message to the peer did not " + + "arrive and the peer repeats sending us the message. We send another ACK msg."); + sendAckMessage(message, true, null); + removeMailboxMessageAfterProcessing(message); + })) + .setup(tasks( + SellerProcessCounterCurrencyTransferStartedMessage.class, + ApplyFilter.class, + getVerifyPeersFeePaymentClass())) + .executeTasks(); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // User interaction + /////////////////////////////////////////////////////////////////////////////////////////// + + public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + SellerEvent event = SellerEvent.PAYMENT_RECEIVED; + expect(anyPhase(Trade.Phase.FIAT_SENT, Trade.Phase.PAYOUT_PUBLISHED) + .with(event) + .preCondition(trade.confirmPermitted())) + .setup(tasks( + ApplyFilter.class, + getVerifyPeersFeePaymentClass(), + SellerSignAndFinalizePayoutTx.class, + SellerBroadcastPayoutTx.class, + SellerSendPayoutTxPublishedMessage.class) + .using(new TradeTaskRunner(trade, + () -> { + resultHandler.handleResult(); + handleTaskRunnerSuccess(event); + }, + (errorMessage) -> { + errorMessageHandler.handleErrorMessage(errorMessage); + handleTaskRunnerFault(event, errorMessage); + }))) + .run(() -> { + trade.setState(Trade.State.SELLER_CONFIRMED_IN_UI_FIAT_PAYMENT_RECEIPT); + processModel.getTradeManager().requestPersistence(); + }) + .executeTasks(); + } + + + @Override + protected void onTradeMessage(TradeMessage message, NodeAddress peer) { + log.info("Received {} from {} with tradeId {} and uid {}", + message.getClass().getSimpleName(), peer, message.getTradeId(), message.getUid()); + + super.onTradeMessage(message, peer); + + if (message instanceof DelayedPayoutTxSignatureResponse) { + handle((DelayedPayoutTxSignatureResponse) message, peer); + } else if (message instanceof ShareBuyerPaymentAccountMessage) { + handle((ShareBuyerPaymentAccountMessage) message, peer); + } else if (message instanceof CounterCurrencyTransferStartedMessage) { + handle((CounterCurrencyTransferStartedMessage) message, peer); + } + } + + abstract protected Class getVerifyPeersFeePaymentClass(); + +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BuyerAsMakerProtocol_v5.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BuyerAsMakerProtocol_v5.java new file mode 100644 index 00000000000..0f5953d4258 --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BuyerAsMakerProtocol_v5.java @@ -0,0 +1,145 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol.bisq_v5; + +import bisq.core.trade.model.bisq_v1.BuyerAsMakerTrade; +import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.MakerProtocol; +import bisq.core.trade.protocol.TradeTaskRunner; +import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureRequest; +import bisq.core.trade.protocol.bisq_v1.messages.DepositTxAndDelayedPayoutTxMessage; +import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxRequest; +import bisq.core.trade.protocol.bisq_v1.messages.PayoutTxPublishedMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; +import bisq.core.trade.protocol.bisq_v1.tasks.CheckIfDaoStateIsInSync; +import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerFinalizesDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerProcessDelayedPayoutTxSignatureRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSendsDelayedPayoutTxSignatureResponse; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSetupDepositTxListener; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSignsDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerVerifiesPreparedDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer_as_maker.BuyerAsMakerCreatesAndSignsDepositTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer_as_maker.BuyerAsMakerSendsInputsForDepositTxResponse; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerCreateAndSignContract; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerProcessesInputsForDepositTxRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerRemovesOpenOffer; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerSetsLockTime; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerVerifyTakerFeePayment; + +import bisq.network.p2p.NodeAddress; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class BuyerAsMakerProtocol_v5 extends BaseBuyerProtocol_v5 implements MakerProtocol { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public BuyerAsMakerProtocol_v5(BuyerAsMakerTrade trade) { + super(trade); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Handle take offer request + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void handleTakeOfferRequest(InputsForDepositTxRequest message, + NodeAddress peer, + ErrorMessageHandler errorMessageHandler) { + expect(phase(Trade.Phase.INIT) + .with(message) + .from(peer)) + .setup(tasks( + CheckIfDaoStateIsInSync.class, + MakerProcessesInputsForDepositTxRequest.class, + ApplyFilter.class, + getVerifyPeersFeePaymentClass(), + MakerSetsLockTime.class, + MakerCreateAndSignContract.class, + BuyerAsMakerCreatesAndSignsDepositTx.class, + BuyerSetupDepositTxListener.class, + BuyerAsMakerSendsInputsForDepositTxResponse.class). + using(new TradeTaskRunner(trade, + () -> handleTaskRunnerSuccess(message), + errorMessage -> { + errorMessageHandler.handleErrorMessage(errorMessage); + handleTaskRunnerFault(message, errorMessage); + })) + .withTimeout(120)) + .executeTasks(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming messages Take offer process + /////////////////////////////////////////////////////////////////////////////////////////// + + protected void handle(DelayedPayoutTxSignatureRequest message, NodeAddress peer) { + expect(phase(Trade.Phase.TAKER_FEE_PUBLISHED) + .with(message) + .from(peer)) + .setup(tasks( + MakerRemovesOpenOffer.class, + BuyerProcessDelayedPayoutTxSignatureRequest.class, + BuyerVerifiesPreparedDelayedPayoutTx.class, + BuyerSignsDelayedPayoutTx.class, + BuyerFinalizesDelayedPayoutTx.class, + BuyerSendsDelayedPayoutTxSignatureResponse.class) + .withTimeout(120)) + .executeTasks(); + } + + @Override + protected void handle(DepositTxAndDelayedPayoutTxMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // User interaction + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + super.onPaymentStarted(resultHandler, errorMessageHandler); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming message Payout tx + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void handle(PayoutTxPublishedMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + @Override + protected Class getVerifyPeersFeePaymentClass() { + return MakerVerifyTakerFeePayment.class; + } +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BuyerAsTakerProtocol_v5.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BuyerAsTakerProtocol_v5.java new file mode 100644 index 00000000000..a31a4bf3376 --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/BuyerAsTakerProtocol_v5.java @@ -0,0 +1,173 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol.bisq_v5; + + +import bisq.core.offer.Offer; +import bisq.core.trade.model.bisq_v1.BuyerAsTakerTrade; +import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.TakerProtocol; +import bisq.core.trade.protocol.TradeMessage; +import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureRequest; +import bisq.core.trade.protocol.bisq_v1.messages.DepositTxAndDelayedPayoutTxMessage; +import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxResponse; +import bisq.core.trade.protocol.bisq_v1.messages.PayoutTxPublishedMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; +import bisq.core.trade.protocol.bisq_v1.tasks.CheckIfDaoStateIsInSync; +import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerFinalizesDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerProcessDelayedPayoutTxSignatureRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSendsDelayedPayoutTxSignatureResponse; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSetupDepositTxListener; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerSignsDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer.BuyerVerifiesPreparedDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer_as_taker.BuyerAsTakerCreatesDepositTxInputs; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer_as_taker.BuyerAsTakerSendsDepositTxMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.buyer_as_taker.BuyerAsTakerSignsDepositTx; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.CreateTakerFeeTx; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerProcessesInputsForDepositTxResponse; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerPublishFeeTx; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerSendInputsForDepositTxRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerVerifyAndSignContract; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerVerifyMakerFeePayment; + +import bisq.network.p2p.NodeAddress; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +import lombok.extern.slf4j.Slf4j; + +import static com.google.common.base.Preconditions.checkNotNull; + +@Slf4j +public class BuyerAsTakerProtocol_v5 extends BaseBuyerProtocol_v5 implements TakerProtocol { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public BuyerAsTakerProtocol_v5(BuyerAsTakerTrade trade) { + super(trade); + + Offer offer = checkNotNull(trade.getOffer()); + processModel.getTradePeer().setPubKeyRing(offer.getPubKeyRing()); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Take offer + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onTakeOffer() { + expect(phase(Trade.Phase.INIT) + .with(TakerEvent.TAKE_OFFER)) + .setup(tasks( + CheckIfDaoStateIsInSync.class, + ApplyFilter.class, + getVerifyPeersFeePaymentClass(), + CreateTakerFeeTx.class, + BuyerAsTakerCreatesDepositTxInputs.class, + TakerSendInputsForDepositTxRequest.class) + .withTimeout(120)) + .run(() -> { + processModel.setTempTradingPeerNodeAddress(trade.getTradingPeerNodeAddress()); + processModel.getTradeManager().requestPersistence(); + }) + .executeTasks(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming messages Take offer process + /////////////////////////////////////////////////////////////////////////////////////////// + + private void handle(InputsForDepositTxResponse message, NodeAddress peer) { + expect(phase(Trade.Phase.INIT) + .with(message) + .from(peer)) + .setup(tasks(TakerProcessesInputsForDepositTxResponse.class, + ApplyFilter.class, + TakerVerifyAndSignContract.class, + TakerPublishFeeTx.class, + BuyerAsTakerSignsDepositTx.class, + BuyerSetupDepositTxListener.class, + BuyerAsTakerSendsDepositTxMessage.class) + .withTimeout(120)) + .executeTasks(); + } + + protected void handle(DelayedPayoutTxSignatureRequest message, NodeAddress peer) { + expect(phase(Trade.Phase.TAKER_FEE_PUBLISHED) + .with(message) + .from(peer)) + .setup(tasks( + BuyerProcessDelayedPayoutTxSignatureRequest.class, + BuyerVerifiesPreparedDelayedPayoutTx.class, + BuyerSignsDelayedPayoutTx.class, + BuyerFinalizesDelayedPayoutTx.class, + BuyerSendsDelayedPayoutTxSignatureResponse.class) + .withTimeout(120)) + .executeTasks(); + } + + @Override + protected void handle(DepositTxAndDelayedPayoutTxMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // User interaction + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + super.onPaymentStarted(resultHandler, errorMessageHandler); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming message Payout tx + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void handle(PayoutTxPublishedMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Message dispatcher + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void onTradeMessage(TradeMessage message, NodeAddress peer) { + super.onTradeMessage(message, peer); + + if (message instanceof InputsForDepositTxResponse) { + handle((InputsForDepositTxResponse) message, peer); + } + } + + @Override + protected Class getVerifyPeersFeePaymentClass() { + return TakerVerifyMakerFeePayment.class; + } +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v5/SellerAsMakerProtocol_v5.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/SellerAsMakerProtocol_v5.java new file mode 100644 index 00000000000..4ca11fe4670 --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/SellerAsMakerProtocol_v5.java @@ -0,0 +1,169 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol.bisq_v5; + + +import bisq.core.trade.model.bisq_v1.SellerAsMakerTrade; +import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.MakerProtocol; +import bisq.core.trade.protocol.TradeMessage; +import bisq.core.trade.protocol.TradeTaskRunner; +import bisq.core.trade.protocol.bisq_v1.messages.CounterCurrencyTransferStartedMessage; +import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureResponse; +import bisq.core.trade.protocol.bisq_v1.messages.DepositTxMessage; +import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxRequest; +import bisq.core.trade.protocol.bisq_v1.messages.ShareBuyerPaymentAccountMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; +import bisq.core.trade.protocol.bisq_v1.tasks.CheckIfDaoStateIsInSync; +import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerCreateAndSignContract; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerProcessesInputsForDepositTxRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerRemovesOpenOffer; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerSetsLockTime; +import bisq.core.trade.protocol.bisq_v1.tasks.maker.MakerVerifyTakerFeePayment; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.MaybeCreateSubAccount; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerCreatesDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerSendDelayedPayoutTxSignatureRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerSignsDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller_as_maker.SellerAsMakerCreatesUnsignedDepositTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller_as_maker.SellerAsMakerFinalizesDepositTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller_as_maker.SellerAsMakerProcessDepositTxMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.seller_as_maker.SellerAsMakerSendsInputsForDepositTxResponse; + +import bisq.network.p2p.NodeAddress; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SellerAsMakerProtocol_v5 extends BaseSellerProtocol_v5 implements MakerProtocol { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public SellerAsMakerProtocol_v5(SellerAsMakerTrade trade) { + super(trade); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Handle take offer request + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void handleTakeOfferRequest(InputsForDepositTxRequest message, + NodeAddress peer, + ErrorMessageHandler errorMessageHandler) { + expect(phase(Trade.Phase.INIT) + .with(message) + .from(peer)) + .setup(tasks( + CheckIfDaoStateIsInSync.class, + MaybeCreateSubAccount.class, + MakerProcessesInputsForDepositTxRequest.class, + ApplyFilter.class, + getVerifyPeersFeePaymentClass(), + MakerSetsLockTime.class, + MakerCreateAndSignContract.class, + SellerAsMakerCreatesUnsignedDepositTx.class, + SellerAsMakerSendsInputsForDepositTxResponse.class) + .using(new TradeTaskRunner(trade, + () -> handleTaskRunnerSuccess(message), + errorMessage -> { + errorMessageHandler.handleErrorMessage(errorMessage); + handleTaskRunnerFault(message, errorMessage); + })) + .withTimeout(120)) + .executeTasks(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming messages Take offer process + /////////////////////////////////////////////////////////////////////////////////////////// + + protected void handle(DepositTxMessage message, NodeAddress peer) { + expect(phase(Trade.Phase.TAKER_FEE_PUBLISHED) + .with(message) + .from(peer)) + .setup(tasks( + MakerRemovesOpenOffer.class, + SellerAsMakerProcessDepositTxMessage.class, + SellerAsMakerFinalizesDepositTx.class, + SellerCreatesDelayedPayoutTx.class, + SellerSignsDelayedPayoutTx.class, + SellerSendDelayedPayoutTxSignatureRequest.class) + .withTimeout(120)) + .executeTasks(); + } + + @Override + protected void handle(DelayedPayoutTxSignatureResponse message, NodeAddress peer) { + super.handle(message, peer); + } + + @Override + protected void handle(ShareBuyerPaymentAccountMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming message when buyer has clicked payment started button + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void handle(CounterCurrencyTransferStartedMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // User interaction + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + super.onPaymentReceived(resultHandler, errorMessageHandler); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Massage dispatcher + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void onTradeMessage(TradeMessage message, NodeAddress peer) { + super.onTradeMessage(message, peer); + + log.info("Received {} from {} with tradeId {} and uid {}", + message.getClass().getSimpleName(), peer, message.getTradeId(), message.getUid()); + + if (message instanceof DepositTxMessage) { + handle((DepositTxMessage) message, peer); + } + } + + @Override + protected Class getVerifyPeersFeePaymentClass() { + return MakerVerifyTakerFeePayment.class; + } +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v5/SellerAsTakerProtocol_v5.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/SellerAsTakerProtocol_v5.java new file mode 100644 index 00000000000..036cf1a6048 --- /dev/null +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v5/SellerAsTakerProtocol_v5.java @@ -0,0 +1,163 @@ +/* + * This file is part of Bisq. + * + * Bisq 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. + * + * Bisq 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 Bisq. If not, see . + */ + +package bisq.core.trade.protocol.bisq_v5; + + +import bisq.core.offer.Offer; +import bisq.core.trade.model.bisq_v1.SellerAsTakerTrade; +import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.protocol.TakerProtocol; +import bisq.core.trade.protocol.TradeMessage; +import bisq.core.trade.protocol.bisq_v1.messages.CounterCurrencyTransferStartedMessage; +import bisq.core.trade.protocol.bisq_v1.messages.DelayedPayoutTxSignatureResponse; +import bisq.core.trade.protocol.bisq_v1.messages.InputsForDepositTxResponse; +import bisq.core.trade.protocol.bisq_v1.messages.ShareBuyerPaymentAccountMessage; +import bisq.core.trade.protocol.bisq_v1.tasks.ApplyFilter; +import bisq.core.trade.protocol.bisq_v1.tasks.CheckIfDaoStateIsInSync; +import bisq.core.trade.protocol.bisq_v1.tasks.TradeTask; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.MaybeCreateSubAccount; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerCreatesDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerSendDelayedPayoutTxSignatureRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.seller.SellerSignsDelayedPayoutTx; +import bisq.core.trade.protocol.bisq_v1.tasks.seller_as_taker.SellerAsTakerCreatesDepositTxInputs; +import bisq.core.trade.protocol.bisq_v1.tasks.seller_as_taker.SellerAsTakerSignsDepositTx; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.CreateTakerFeeTx; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerProcessesInputsForDepositTxResponse; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerPublishFeeTx; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerSendInputsForDepositTxRequest; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerVerifyAndSignContract; +import bisq.core.trade.protocol.bisq_v1.tasks.taker.TakerVerifyMakerFeePayment; + +import bisq.network.p2p.NodeAddress; + +import bisq.common.handlers.ErrorMessageHandler; +import bisq.common.handlers.ResultHandler; + +import lombok.extern.slf4j.Slf4j; + +import static com.google.common.base.Preconditions.checkNotNull; + +@Slf4j +public class SellerAsTakerProtocol_v5 extends BaseSellerProtocol_v5 implements TakerProtocol { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public SellerAsTakerProtocol_v5(SellerAsTakerTrade trade) { + super(trade); + Offer offer = checkNotNull(trade.getOffer()); + processModel.getTradePeer().setPubKeyRing(offer.getPubKeyRing()); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // User interaction: Take offer + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onTakeOffer() { + expect(phase(Trade.Phase.INIT) + .with(TakerEvent.TAKE_OFFER) + .from(trade.getTradingPeerNodeAddress())) + .setup(tasks( + CheckIfDaoStateIsInSync.class, + MaybeCreateSubAccount.class, + ApplyFilter.class, + getVerifyPeersFeePaymentClass(), + CreateTakerFeeTx.class, + SellerAsTakerCreatesDepositTxInputs.class, + TakerSendInputsForDepositTxRequest.class) + .withTimeout(120)) + .executeTasks(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming messages Take offer process + /////////////////////////////////////////////////////////////////////////////////////////// + + private void handle(InputsForDepositTxResponse message, NodeAddress peer) { + expect(phase(Trade.Phase.INIT) + .with(message) + .from(peer)) + .setup(tasks( + TakerProcessesInputsForDepositTxResponse.class, + ApplyFilter.class, + TakerVerifyAndSignContract.class, + TakerPublishFeeTx.class, + SellerAsTakerSignsDepositTx.class, + SellerCreatesDelayedPayoutTx.class, + SellerSignsDelayedPayoutTx.class, + SellerSendDelayedPayoutTxSignatureRequest.class) + .withTimeout(120)) + .executeTasks(); + } + + @Override + protected void handle(DelayedPayoutTxSignatureResponse message, NodeAddress peer) { + super.handle(message, peer); + } + + @Override + protected void handle(ShareBuyerPaymentAccountMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Incoming message when buyer has clicked payment started button + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void handle(CounterCurrencyTransferStartedMessage message, NodeAddress peer) { + super.handle(message, peer); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // User interaction + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + super.onPaymentReceived(resultHandler, errorMessageHandler); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Massage dispatcher + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void onTradeMessage(TradeMessage message, NodeAddress peer) { + super.onTradeMessage(message, peer); + + log.info("Received {} from {} with tradeId {} and uid {}", + message.getClass().getSimpleName(), peer, message.getTradeId(), message.getUid()); + + if (message instanceof InputsForDepositTxResponse) { + handle((InputsForDepositTxResponse) message, peer); + } + } + + @Override + protected Class getVerifyPeersFeePaymentClass() { + return TakerVerifyMakerFeePayment.class; + } +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapBuyerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapBuyerAsTakerProtocol.java index 943806038e4..245149a4ccf 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapBuyerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapBuyerAsTakerProtocol.java @@ -37,7 +37,7 @@ import lombok.extern.slf4j.Slf4j; import static bisq.core.trade.model.bsq_swap.BsqSwapTrade.State.PREPARATION; -import static bisq.core.trade.protocol.bisq_v1.TakerProtocol.TakerEvent.TAKE_OFFER; +import static bisq.core.trade.protocol.TakerProtocol.TakerEvent.TAKE_OFFER; import static com.google.common.base.Preconditions.checkNotNull; @Slf4j diff --git a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapSellerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapSellerAsTakerProtocol.java index f055d7f32fe..fffdba9f76b 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapSellerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapSellerAsTakerProtocol.java @@ -39,7 +39,7 @@ import static bisq.core.trade.model.bsq_swap.BsqSwapTrade.State.COMPLETED; import static bisq.core.trade.model.bsq_swap.BsqSwapTrade.State.PREPARATION; -import static bisq.core.trade.protocol.bisq_v1.TakerProtocol.TakerEvent.TAKE_OFFER; +import static bisq.core.trade.protocol.TakerProtocol.TakerEvent.TAKE_OFFER; import static com.google.common.base.Preconditions.checkNotNull; @Slf4j diff --git a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapTakerProtocol.java index 8b339f0a1fe..f38b2559638 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/BsqSwapTakerProtocol.java @@ -17,7 +17,7 @@ package bisq.core.trade.protocol.bsq_swap; -import bisq.core.trade.protocol.bisq_v1.TakerProtocol; +import bisq.core.trade.protocol.TakerProtocol; public interface BsqSwapTakerProtocol extends TakerProtocol { } diff --git a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java index 02612ee025f..0a24ae350c2 100644 --- a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java +++ b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java @@ -28,7 +28,7 @@ import bisq.core.trade.model.Tradable; import bisq.core.trade.model.bisq_v1.SellerTrade; import bisq.core.trade.model.bisq_v1.Trade; -import bisq.core.trade.protocol.bisq_v1.SellerProtocol; +import bisq.core.trade.protocol.SellerProtocol; import bisq.core.trade.txproof.AssetTxProofResult; import bisq.core.trade.txproof.AssetTxProofService; import bisq.core.user.AutoConfirmSettings; 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 519dba1295d..5e92290ab97 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 @@ -53,9 +53,9 @@ import bisq.core.trade.model.bisq_v1.BuyerTrade; import bisq.core.trade.model.bisq_v1.SellerTrade; import bisq.core.trade.model.bisq_v1.Trade; -import bisq.core.trade.protocol.bisq_v1.BuyerProtocol; +import bisq.core.trade.protocol.BuyerProtocol; +import bisq.core.trade.protocol.SellerProtocol; import bisq.core.trade.protocol.bisq_v1.DisputeProtocol; -import bisq.core.trade.protocol.bisq_v1.SellerProtocol; import bisq.core.user.Preferences; import bisq.core.util.FormattingUtils; import bisq.core.util.coin.CoinFormatter; diff --git a/desktop/src/main/java/bisq/desktop/main/settings/about/AboutView.java b/desktop/src/main/java/bisq/desktop/main/settings/about/AboutView.java index 5dcedaf1528..113df7769cb 100644 --- a/desktop/src/main/java/bisq/desktop/main/settings/about/AboutView.java +++ b/desktop/src/main/java/bisq/desktop/main/settings/about/AboutView.java @@ -91,7 +91,7 @@ public void initialize() { Version.P2P_NETWORK_VERSION, Version.getP2PMessageVersion(), Version.LOCAL_DB_VERSION, - Version.TRADE_PROTOCOL_VERSION)); + Version.getTradeProtocolVersion())); addTitledGroupBg(root, ++gridRow, 18, Res.get("setting.about.shortcuts"), Layout.GROUP_DISTANCE);