From 090f2e742866e10992a27c9082bbd62eb1854a5d Mon Sep 17 00:00:00 2001
From: Manfred Karrer <mk@nucleo.io>
Date: Mon, 9 Mar 2015 12:45:56 +0100
Subject: [PATCH] Refactor check if offer is available process

---
 .../main/portfolio/offer/OffersDataModel.java |   6 +-
 .../gui/main/trade/offerbook/OfferBook.java   |  13 +-
 .../main/trade/offerbook/OfferBookView.java   |   5 +-
 .../trade/takeoffer/TakeOfferDataModel.java   |  67 +-------
 .../main/trade/takeoffer/TakeOfferView.java   |  38 ++--
 .../trade/takeoffer/TakeOfferViewModel.java   |   3 +-
 .../main/java/io/bitsquare/offer/Offer.java   |  36 +++-
 .../java/io/bitsquare/trade/TradeManager.java | 162 ++++++++++--------
 .../bitsquare/trade/TradeMessageService.java  |  10 +-
 ...Listener.java => SendMessageListener.java} |   6 +-
 .../trade/OfferMessage.java}                  |   7 +-
 .../offerer/BuyerAcceptsOfferProtocol.java    |  24 ++-
 ...a => IsOfferAvailableResponseMessage.java} |  14 +-
 .../offerer/tasks/HandleTakeOfferRequest.java |  19 +-
 .../tasks/IsOfferAvailableResponse.java       |  51 ++++++
 .../tasks/RequestTakerDepositPayment.java     |   8 +-
 .../offerer/tasks/SendDepositTxIdToTaker.java |   8 +-
 .../offerer/tasks/SendSignedPayoutTx.java     |   8 +-
 .../RequestIsOfferAvailableProtocol.java      | 116 +++++++++++++
 .../trade/taker/SellerTakesOfferProtocol.java |  43 ++++-
 .../RequestIsOfferAvailableMessage.java       |  14 +-
 .../trade/taker/tasks/GetPeerAddress.java     |   6 +-
 .../taker/tasks/RequestIsOfferAvailable.java  |  52 ++++++
 .../trade/taker/tasks/RequestTakeOffer.java   |  15 +-
 .../taker/tasks/SendPayoutTxToOfferer.java    |   8 +-
 .../tasks/SendSignedTakerDepositTxAsHex.java  |   8 +-
 .../tasks/SendTakeOfferFeePayedTxId.java      |   8 +-
 .../tomp2p/TomP2PTradeMessageService.java     |  35 ++--
 28 files changed, 530 insertions(+), 260 deletions(-)
 rename gui/src/main/java/io/bitsquare/trade/listeners/{OutgoingMessageListener.java => SendMessageListener.java} (89%)
 rename gui/src/main/java/io/bitsquare/trade/{listeners/IncomingMessageListener.java => protocol/trade/OfferMessage.java} (81%)
 rename gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/messages/{RespondToIsOfferAvailableMessage.java => IsOfferAvailableResponseMessage.java} (75%)
 create mode 100644 gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/IsOfferAvailableResponse.java
 create mode 100644 gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/RequestIsOfferAvailableProtocol.java
 create mode 100644 gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestIsOfferAvailable.java

diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java
index 1477be425f..66c9cab0b5 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java
@@ -64,17 +64,17 @@ class OffersDataModel implements Activatable, DataModel {
     @Override
     public void activate() {
         list.clear();
-        list.addAll(tradeManager.getOffers().values().stream().map(OfferListItem::new).collect(Collectors.toList()));
+        list.addAll(tradeManager.getOpenOffers().values().stream().map(OfferListItem::new).collect(Collectors.toList()));
 
         // we sort by date, earliest first
         list.sort((o1, o2) -> o2.getOffer().getCreationDate().compareTo(o1.getOffer().getCreationDate()));
 
-        tradeManager.getOffers().addListener(offerMapChangeListener);
+        tradeManager.getOpenOffers().addListener(offerMapChangeListener);
     }
 
     @Override
     public void deactivate() {
-        tradeManager.getOffers().removeListener(offerMapChangeListener);
+        tradeManager.getOpenOffers().removeListener(offerMapChangeListener);
     }
 
     void removeOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java
index 1db70fc1c0..d5c363d281 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java
@@ -22,6 +22,7 @@ import io.bitsquare.locale.Country;
 import io.bitsquare.locale.CurrencyUtil;
 import io.bitsquare.offer.Offer;
 import io.bitsquare.offer.OfferBookService;
+import io.bitsquare.trade.TradeManager;
 import io.bitsquare.user.User;
 import io.bitsquare.util.Utilities;
 
@@ -68,12 +69,12 @@ public class OfferBook {
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     @Inject
-    OfferBook(OfferBookService offerBookService, User user) {
+    OfferBook(OfferBookService offerBookService, User user, TradeManager tradeManager) {
         this.offerBookService = offerBookService;
         this.user = user;
 
         bankAccountChangeListener = (observableValue, oldValue, newValue) -> setBankAccount(newValue);
-        invalidationListener = (ov, oldValue, newValue) -> requestOffers();
+        invalidationListener = (ov, oldValue, newValue) -> requestGetOffers();
 
         remoteOfferBookListener = new OfferBookService.Listener() {
             @Override
@@ -90,6 +91,12 @@ public class OfferBook {
 
             @Override
             public void onOfferRemoved(Offer offer) {
+                // Update state in case that that offer is used in the take offer screen, so it gets updated correctly
+                offer.setState(Offer.State.OFFER_REMOVED);
+                
+                // clean up possible references in tradeManager 
+                tradeManager.handleRemovedOffer(offer);
+                
                 offerBookListItems.removeIf(item -> item.getOffer().getId().equals(offer.getId()));
             }
         };
@@ -159,7 +166,7 @@ public class OfferBook {
         }
     }
 
-    private void requestOffers() {
+    private void requestGetOffers() {
         offerBookService.getOffers(fiatCode);
     }
 
diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java
index 9aa4c6ee61..16f4d5efc7 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java
@@ -216,9 +216,12 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
     }
 
     private void takeOffer(Offer offer) {
-
         if (model.isRegistered()) {
             if (offer.getDirection() == Direction.BUY) {
+                // reset available state
+                if (offer.getState() != Offer.State.OFFER_REMOVED)
+                    offer.setState(Offer.State.UNKNOWN);
+
                 offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer);
             }
             else {
diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferDataModel.java
index 2794d296dd..517d8b190f 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferDataModel.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferDataModel.java
@@ -21,16 +21,11 @@ import io.bitsquare.btc.AddressEntry;
 import io.bitsquare.btc.FeePolicy;
 import io.bitsquare.btc.WalletService;
 import io.bitsquare.btc.listeners.BalanceListener;
-import io.bitsquare.network.Peer;
 import io.bitsquare.offer.Offer;
 import io.bitsquare.persistence.Persistence;
 import io.bitsquare.settings.Preferences;
 import io.bitsquare.trade.Trade;
 import io.bitsquare.trade.TradeManager;
-import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.GetPeerAddressListener;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
-import io.bitsquare.trade.protocol.trade.taker.messages.RequestIsOfferAvailableMessage;
 
 import org.bitcoinj.core.Coin;
 import org.bitcoinj.utils.ExchangeRate;
@@ -61,15 +56,8 @@ import org.slf4j.LoggerFactory;
 class TakeOfferDataModel implements Activatable, DataModel {
     private static final Logger log = LoggerFactory.getLogger(TakeOfferDataModel.class);
 
-    enum OfferAvailableState {
-        UNKNOWN,
-        OFFER_NOT_AVAILABLE,
-        OFFER_AVAILABLE
-    }
-
     private final TradeManager tradeManager;
     private final WalletService walletService;
-    private TradeMessageService tradeMessageService;
     private final Preferences preferences;
     private final Persistence persistence;
 
@@ -91,19 +79,15 @@ class TakeOfferDataModel implements Activatable, DataModel {
     final ObjectProperty<Coin> offerFeeAsCoin = new SimpleObjectProperty<>();
     final ObjectProperty<Coin> networkFeeAsCoin = new SimpleObjectProperty<>();
 
-    final ObjectProperty<OfferAvailableState> offerIsAvailable = new SimpleObjectProperty<>(OfferAvailableState
-            .UNKNOWN);
-
-    // 
-    private boolean isActivated;
+    final ObjectProperty<Offer.State> offerIsAvailable = new SimpleObjectProperty<>(Offer.State.UNKNOWN);
 
     @Inject
-    public TakeOfferDataModel(TradeManager tradeManager, WalletService walletService, TradeMessageService tradeMessageService,
+    public TakeOfferDataModel(TradeManager tradeManager, 
+                              WalletService walletService,
                               Preferences preferences,
                               Persistence persistence) {
         this.tradeManager = tradeManager;
         this.walletService = walletService;
-        this.tradeMessageService = tradeMessageService;
         this.preferences = preferences;
         this.persistence = persistence;
 
@@ -113,13 +97,11 @@ class TakeOfferDataModel implements Activatable, DataModel {
 
     @Override
     public void activate() {
-        isActivated = true;
         btcCode.bind(preferences.btcDenominationProperty());
     }
 
     @Override
     public void deactivate() {
-        isActivated = false;
         btcCode.unbind();
     }
 
@@ -148,49 +130,12 @@ class TakeOfferDataModel implements Activatable, DataModel {
         });
         updateBalance(walletService.getBalanceForAddress(addressEntry.getAddress()));
 
-        getPeerAddress(offer);
-    }
-
-    // TODO: Should be moved to a domain and handled with add/remove listeners instead of isActivated
-    // or maybe with rx?
-    private void getPeerAddress(Offer offer) {
-        tradeMessageService.getPeerAddress(offer.getMessagePublicKey(), new GetPeerAddressListener() {
-            @Override
-            public void onResult(Peer peer) {
-                if (isActivated)
-                    isOfferAvailable(peer, offer.getId());
-            }
-
-            @Override
-            public void onFailed() {
-                if (isActivated)
-                    log.error("The offerers address have not been found. That should never happen.");
-            }
+        offer.getStateProperty().addListener((observable, oldValue, newValue) -> {
+            offerIsAvailable.set(newValue);
         });
+        tradeManager.requestIsOfferAvailable(offer);
     }
 
-    private void isOfferAvailable(Peer peer, String offerId) {
-        tradeMessageService.sendMessage(peer, new RequestIsOfferAvailableMessage(offerId),
-                new OutgoingMessageListener() {
-                    @Override
-                    public void onResult() {
-                        if (isActivated) {
-                            log.trace("RequestIsOfferAvailableMessage successfully arrived at peer");
-                            offerIsAvailable.set(OfferAvailableState.OFFER_AVAILABLE);
-                        }
-                    }
-
-                    @Override
-                    public void onFailed() {
-                        if (isActivated) {
-                            log.error("RequestIsOfferAvailableMessage  did not arrive at peer");
-                            offerIsAvailable.set(OfferAvailableState.OFFER_NOT_AVAILABLE);
-                        }
-                    }
-                });
-    }
-
-
     void takeOffer() {
         final Trade trade = tradeManager.takeOffer(amountAsCoin.get(), offer);
         trade.stateProperty().addListener((ov, oldValue, newValue) -> {
diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferView.java
index 9ab8f8df72..fafff6f883 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferView.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferView.java
@@ -140,22 +140,30 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
         acceptedLanguagesTextField.setText(model.getAcceptedLanguages());
         acceptedArbitratorsTextField.setText(model.getAcceptedArbitrators());
 
-        model.offerIsAvailable.addListener((ov, oldValue, newValue) -> {
-            isOfferAvailableLabel.setVisible(false);
-            isOfferAvailableLabel.setManaged(false);
-            isOfferAvailableProgressIndicator.setProgress(0);
-            isOfferAvailableProgressIndicator.setVisible(false);
-            isOfferAvailableProgressIndicator.setManaged(false);
+        model.offerIsAvailable.addListener((ov, oldValue, newValue) -> handleOfferIsAvailableState(newValue));
+        handleOfferIsAvailableState(model.offerIsAvailable.get());
+    }
 
-            if ((newValue == TakeOfferDataModel.OfferAvailableState.OFFER_AVAILABLE)) {
-                showPaymentInfoScreenButton.setVisible(true);
-            }
-            else if ((newValue == TakeOfferDataModel.OfferAvailableState.OFFER_NOT_AVAILABLE)) {
-                Popups.openWarningPopup("You cannot take that offer",
-                        "The offerer is either offline or the offer was already taken by another trader.");
-                close();
-            }
-        });
+    private void handleOfferIsAvailableState(Offer.State state) {
+        isOfferAvailableLabel.setVisible(false);
+        isOfferAvailableLabel.setManaged(false);
+        isOfferAvailableProgressIndicator.setProgress(0);
+        isOfferAvailableProgressIndicator.setVisible(false);
+        isOfferAvailableProgressIndicator.setManaged(false);
+
+        if ((state == Offer.State.OFFER_AVAILABLE)) {
+            showPaymentInfoScreenButton.setVisible(true);
+        }
+        else if ((state == Offer.State.OFFER_NOT_AVAILABLE)) {
+            Popups.openWarningPopup("You cannot take that offer",
+                    "The offerer is either offline or the offer was already taken by another trader.");
+            close();
+        }
+        else if ((state == Offer.State.OFFER_REMOVED)) {
+            Popups.openWarningPopup("You cannot take that offer",
+                    "The offerer has been removed in the meantime.");
+            close();
+        }
     }
 
     public void configCloseHandlers(BooleanProperty tabIsClosable) {
diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java
index c57b8e9fc6..818b213fa9 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java
@@ -82,8 +82,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
     final BooleanProperty showWarningInvalidBtcDecimalPlaces = new SimpleBooleanProperty();
     final BooleanProperty showTransactionPublishedScreen = new SimpleBooleanProperty();
     final BooleanProperty tabIsClosable = new SimpleBooleanProperty(true);
-    final ObjectProperty<TakeOfferDataModel.OfferAvailableState> offerIsAvailable =
-            new SimpleObjectProperty<>(TakeOfferDataModel.OfferAvailableState.UNKNOWN);
+    final ObjectProperty<Offer.State> offerIsAvailable = new SimpleObjectProperty<>(Offer.State.UNKNOWN);
 
     final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>();
 
diff --git a/gui/src/main/java/io/bitsquare/offer/Offer.java b/gui/src/main/java/io/bitsquare/offer/Offer.java
index bf9336c11d..9df82065e1 100644
--- a/gui/src/main/java/io/bitsquare/offer/Offer.java
+++ b/gui/src/main/java/io/bitsquare/offer/Offer.java
@@ -34,6 +34,9 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+
 import static com.google.common.base.Preconditions.*;
 import static io.bitsquare.btc.Restrictions.MIN_TRADE_AMOUNT;
 
@@ -42,6 +45,14 @@ import static io.bitsquare.btc.Restrictions.MIN_TRADE_AMOUNT;
 public class Offer implements Serializable {
     private static final long serialVersionUID = -971164804305475826L;
 
+
+    public enum State {
+        UNKNOWN,
+        OFFER_AVAILABLE,
+        OFFER_NOT_AVAILABLE,
+        OFFER_REMOVED
+    }
+
     // key attributes for lookup
     private final Direction direction;
     private final Currency currency;
@@ -64,8 +75,10 @@ public class Offer implements Serializable {
     private final List<Locale> acceptedLanguageLocales;
     private final String bankAccountUID;
     private final List<Arbitrator> arbitrators;
-    
+
     private String offerFeePaymentTxID;
+    private State state = State.UNKNOWN;
+    private transient ObjectProperty<State> stateProperty; // don't access directly, use getStateProperty()
 
 
     ///////////////////////////////////////////////////////////////////////////////////////////
@@ -103,6 +116,7 @@ public class Offer implements Serializable {
         this.acceptedLanguageLocales = acceptedLanguageLocales;
 
         creationDate = new Date();
+        getStateProperty().set(state);
     }
 
 
@@ -110,11 +124,11 @@ public class Offer implements Serializable {
     // Setters
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    public PublicKey getMessagePublicKey() {
-        return messagePublicKey;
+    public void setState(State state) {
+        this.state = state;
+        getStateProperty().set(state);
     }
 
-
     ///////////////////////////////////////////////////////////////////////////////////////////
     // Getters
     ///////////////////////////////////////////////////////////////////////////////////////////
@@ -198,10 +212,24 @@ public class Offer implements Serializable {
         return bankAccountUID;
     }
 
+    public PublicKey getMessagePublicKey() {
+        return messagePublicKey;
+    }
+
     public Date getCreationDate() {
         return creationDate;
     }
 
+    public State getState() {
+        return state;
+    }
+
+    public ObjectProperty<State> getStateProperty() {
+        if (stateProperty == null)
+            stateProperty = new SimpleObjectProperty<>(state);
+        return stateProperty;
+    }
+
     public void validate() throws Exception {
         checkNotNull(getAcceptedCountries(), "AcceptedCountries is null");
         checkNotNull(getAcceptedLanguageLocales(), "AcceptedLanguageLocales is null");
diff --git a/gui/src/main/java/io/bitsquare/trade/TradeManager.java b/gui/src/main/java/io/bitsquare/trade/TradeManager.java
index c094e516a3..a6d831a833 100644
--- a/gui/src/main/java/io/bitsquare/trade/TradeManager.java
+++ b/gui/src/main/java/io/bitsquare/trade/TradeManager.java
@@ -29,16 +29,18 @@ import io.bitsquare.offer.Offer;
 import io.bitsquare.offer.OfferBookService;
 import io.bitsquare.persistence.Persistence;
 import io.bitsquare.trade.handlers.TransactionResultHandler;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
 import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
+import io.bitsquare.trade.protocol.trade.OfferMessage;
 import io.bitsquare.trade.protocol.trade.TradeMessage;
 import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol;
 import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocolListener;
 import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
 import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
+import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
 import io.bitsquare.trade.protocol.trade.offerer.messages.RequestTakerDepositPaymentMessage;
-import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToIsOfferAvailableMessage;
 import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
+import io.bitsquare.trade.protocol.trade.offerer.tasks.IsOfferAvailableResponse;
+import io.bitsquare.trade.protocol.trade.taker.RequestIsOfferAvailableProtocol;
 import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol;
 import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocolListener;
 import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
@@ -69,6 +71,8 @@ import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * The domain for the trading
  * TODO: Too messy, need to be improved a lot....
@@ -88,8 +92,9 @@ public class TradeManager {
     //TODO store TakerAsSellerProtocol in trade
     private final Map<String, SellerTakesOfferProtocol> takerAsSellerProtocolMap = new HashMap<>();
     private final Map<String, BuyerAcceptsOfferProtocol> offererAsBuyerProtocolMap = new HashMap<>();
+    private final Map<String, RequestIsOfferAvailableProtocol> requestIsOfferAvailableProtocolMap = new HashMap<>();
 
-    private final ObservableMap<String, Offer> offers = FXCollections.observableHashMap();
+    private final ObservableMap<String, Offer> openOffers = FXCollections.observableHashMap();
     private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
     private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
 
@@ -118,7 +123,7 @@ public class TradeManager {
 
         Object offersObject = persistence.read(this, "offers");
         if (offersObject instanceof Map) {
-            offers.putAll((Map<String, Offer>) offersObject);
+            openOffers.putAll((Map<String, Offer>) offersObject);
         }
 
         Object pendingTradesObject = persistence.read(this, "pendingTrades");
@@ -131,7 +136,7 @@ public class TradeManager {
             closedTrades.putAll((Map<String, Trade>) closedTradesObject);
         }
 
-        tradeMessageService.addIncomingMessageListener(this::onIncomingTradeMessage);
+        tradeMessageService.addHandleNewMessageListener(this::handleNewMessage);
     }
 
 
@@ -140,7 +145,7 @@ public class TradeManager {
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     public void cleanup() {
-        tradeMessageService.removeIncomingMessageListener(this::onIncomingTradeMessage);
+        tradeMessageService.removeHandleNewMessageListener(this::handleNewMessage);
     }
 
 
@@ -187,15 +192,15 @@ public class TradeManager {
     }
 
     private void saveOffer(Offer offer) {
-        offers.put(offer.getId(), offer);
+        openOffers.put(offer.getId(), offer);
         persistOffers();
     }
 
     public void requestRemoveOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
         offerBookService.removeOffer(offer,
                 () -> {
-                    if (offers.containsKey(offer.getId())) {
-                        offers.remove(offer.getId());
+                    if (openOffers.containsKey(offer.getId())) {
+                        openOffers.remove(offer.getId());
                         persistOffers();
                         resultHandler.handleResult();
                     }
@@ -241,8 +246,8 @@ public class TradeManager {
 
     private void createOffererAsBuyerProtocol(String offerId, Peer sender) {
         log.trace("createOffererAsBuyerProtocol offerId = " + offerId);
-        if (offers.containsKey(offerId)) {
-            Offer offer = offers.get(offerId);
+        if (openOffers.containsKey(offerId)) {
+            Offer offer = openOffers.get(offerId);
 
             Trade trade = createTrade(offer);
             currentPendingTrade = trade;
@@ -368,6 +373,14 @@ public class TradeManager {
             @Override
             public void onFault(Throwable throwable, SellerTakesOfferProtocol.State state) {
                 log.error("onFault: " + throwable.getMessage() + " / " + state);
+                switch (state) {
+                    case GetPeerAddress:
+                        // TODO add unreachable node to a local ignore list in case of repeated failures
+                        break;
+                    case RequestTakeOffer:
+                        // TODO add unreachable node to a local ignore list in case of repeated failures
+                        break;
+                }
             }
 
             // probably not needed
@@ -379,7 +392,12 @@ public class TradeManager {
         };
 
         SellerTakesOfferProtocol sellerTakesOfferProtocol = new SellerTakesOfferProtocol(
-                trade, listener, tradeMessageService, walletService, blockChainService, signatureService,
+                trade,
+                listener,
+                tradeMessageService,
+                walletService,
+                blockChainService,
+                signatureService,
                 user);
         takerAsSellerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
         sellerTakesOfferProtocol.start();
@@ -407,62 +425,80 @@ public class TradeManager {
         takerAsSellerProtocolMap.get(tradeId).onUIEventFiatReceived();
     }
 
+    public void requestIsOfferAvailable(Offer offer) {
+        if (!requestIsOfferAvailableProtocolMap.containsKey(offer.getId())) {
+            RequestIsOfferAvailableProtocol protocol = new RequestIsOfferAvailableProtocol(offer, tradeMessageService);
+            requestIsOfferAvailableProtocolMap.put(offer.getId(), protocol);
+            protocol.start();
+        }
+        else {
+            log.warn("requestIsOfferAvailable already called for offer with ID:" + offer.getId());
+        }
+    }
+
+    public void handleRemovedOffer(Offer offer) {
+        requestIsOfferAvailableProtocolMap.remove(offer.getId());
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////////////
-    // Process incoming tradeMessages
+    // Process new tradeMessages
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     // Routes the incoming messages to the responsible protocol
-    private void onIncomingTradeMessage(Message message, Peer sender) {
-        if (!(message instanceof TradeMessage))
-            throw new IllegalArgumentException("message must be of type TradeMessage");
-        TradeMessage tradeMessage = (TradeMessage) message;
+    private void handleNewMessage(Message message, Peer sender) {
+        log.trace("handleNewMessage: message = " + message.getClass().getSimpleName());
+        log.trace("handleNewMessage: sender = " + sender);
 
-        log.trace("onIncomingTradeMessage instance " + tradeMessage.getClass().getSimpleName());
-        log.trace("onIncomingTradeMessage sender " + sender);
-
-        String tradeId = tradeMessage.getTradeId();
-        if (tradeId != null) {
-            if (tradeMessage instanceof RequestIsOfferAvailableMessage) {
-                // TODO Does not fit in any of the 2 protocols, but should not be here as well...
-                // Lets keep it until we refactor the trade process
-                boolean isOfferOpen = getTrade(tradeId) == null;
-                RespondToIsOfferAvailableMessage replyMessage =
-                        new RespondToIsOfferAvailableMessage(tradeId, isOfferOpen);
-                tradeMessageService.sendMessage(sender, replyMessage, new OutgoingMessageListener() {
-                    @Override
-                    public void onResult() {
-                        log.trace("RespondToTakeOfferRequestMessage successfully arrived at peer");
-                    }
-
-                    @Override
-                    public void onFailed() {
-                        log.error("AcceptTakeOfferRequestMessage  did not arrive at peer");
-                    }
-                });
+        if (message instanceof OfferMessage) {
+            OfferMessage offerMessage = (OfferMessage) message;
+            // Before starting any take offer activity we check if the offer is still available.
+            if (offerMessage instanceof RequestIsOfferAvailableMessage) {
+                // That message arrives at the offerer and he returns if the offer is still available (if there is no trade already created with that offerId).
+                String offerId = offerMessage.getOfferId();
+                checkNotNull(offerId);
+                boolean isOfferOpen = getTrade(offerId) == null;
+                // no handling of results or faults needed
+                IsOfferAvailableResponse.run(sender, tradeMessageService, offerId, isOfferOpen);
             }
-            else if (tradeMessage instanceof RequestTakeOfferMessage) {
+            else if (offerMessage instanceof IsOfferAvailableResponseMessage) {
+                // That message arrives at the taker in response to a previous requestIsOfferAvailable call.
+                // It might be that the offer got removed form the offer book, so lets check if its still there.
+                if (requestIsOfferAvailableProtocolMap.containsKey(offerMessage.getOfferId())) {
+                    RequestIsOfferAvailableProtocol protocol = requestIsOfferAvailableProtocolMap.get(offerMessage.getOfferId());
+                    protocol.handleIsOfferAvailableResponseMessage((IsOfferAvailableResponseMessage) offerMessage);
+                    requestIsOfferAvailableProtocolMap.remove(offerMessage.getOfferId());
+                }
+                else {
+                    log.info("Offer might have been removed in the meantime. No protocol found for offer with ID:" + offerMessage.getOfferId());
+                }
+            }
+            else {
+                log.error("Incoming offerMessage not supported. " + offerMessage);
+            }
+        }
+        else if (message instanceof TradeMessage) {
+            TradeMessage tradeMessage = (TradeMessage) message;
+            String tradeId = tradeMessage.getTradeId();
+            checkNotNull(tradeId);
+
+            if (tradeMessage instanceof RequestTakeOfferMessage) {
                 createOffererAsBuyerProtocol(tradeId, sender);
             }
             else if (tradeMessage instanceof RespondToTakeOfferRequestMessage) {
-                takerAsSellerProtocolMap.get(tradeId).onRespondToTakeOfferRequestMessage(
-                        (RespondToTakeOfferRequestMessage) tradeMessage);
+                takerAsSellerProtocolMap.get(tradeId).onRespondToTakeOfferRequestMessage((RespondToTakeOfferRequestMessage) tradeMessage);
             }
             else if (tradeMessage instanceof TakeOfferFeePayedMessage) {
-                offererAsBuyerProtocolMap.get(tradeId).onTakeOfferFeePayedMessage((TakeOfferFeePayedMessage)
-                        tradeMessage);
+                offererAsBuyerProtocolMap.get(tradeId).onTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage);
             }
             else if (tradeMessage instanceof RequestTakerDepositPaymentMessage) {
-                takerAsSellerProtocolMap.get(tradeId).onRequestTakerDepositPaymentMessage(
-                        (RequestTakerDepositPaymentMessage) tradeMessage);
+                takerAsSellerProtocolMap.get(tradeId).onRequestTakerDepositPaymentMessage((RequestTakerDepositPaymentMessage) tradeMessage);
             }
             else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {
-                offererAsBuyerProtocolMap.get(tradeId).onRequestOffererPublishDepositTxMessage(
-                        (RequestOffererPublishDepositTxMessage) tradeMessage);
+                offererAsBuyerProtocolMap.get(tradeId).onRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
             }
             else if (tradeMessage instanceof DepositTxPublishedMessage) {
                 persistPendingTrades();
-                takerAsSellerProtocolMap.get(tradeId).onDepositTxPublishedMessage((DepositTxPublishedMessage)
-                        tradeMessage);
+                takerAsSellerProtocolMap.get(tradeId).onDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
             }
             else if (tradeMessage instanceof BankTransferInitedMessage) {
                 // Here happened a null pointer. I assume the only possible reason was that we got a null for the 
@@ -471,29 +507,21 @@ public class TradeManager {
                 // For getting better info we add a check. tradeId is checked above.
                 if (takerAsSellerProtocolMap.get(tradeId) == null)
                     log.error("takerAsSellerProtocolMap.get(tradeId) = null. That must not happen.");
-                takerAsSellerProtocolMap.get(tradeId).onBankTransferInitedMessage((BankTransferInitedMessage)
-                        tradeMessage);
+                takerAsSellerProtocolMap.get(tradeId).onBankTransferInitedMessage((BankTransferInitedMessage) tradeMessage);
             }
             else if (tradeMessage instanceof PayoutTxPublishedMessage) {
-                offererAsBuyerProtocolMap.get(tradeId).onPayoutTxPublishedMessage((PayoutTxPublishedMessage)
-                        tradeMessage);
+                offererAsBuyerProtocolMap.get(tradeId).onPayoutTxPublishedMessage((PayoutTxPublishedMessage) tradeMessage);
+            }
+            else {
+                log.error("Incoming tradeMessage not supported. " + tradeMessage);
             }
         }
         else {
-            log.error("tradeId from onIncomingTradeMessage is null. That must not happen.");
+            log.error("Incoming message not supported. " + message);
         }
     }
 
 
-    ///////////////////////////////////////////////////////////////////////////////////////////
-    // Utils
-    ///////////////////////////////////////////////////////////////////////////////////////////
-
-    public boolean isOfferAlreadyInTrades(Offer offer) {
-        return pendingTrades.containsKey(offer.getId());
-    }
-
-
     ///////////////////////////////////////////////////////////////////////////////////////////
     // Setters
     ///////////////////////////////////////////////////////////////////////////////////////////
@@ -507,8 +535,8 @@ public class TradeManager {
     // Getters
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    public ObservableMap<String, Offer> getOffers() {
-        return offers;
+    public ObservableMap<String, Offer> getOpenOffers() {
+        return openOffers;
     }
 
     public ObservableMap<String, Trade> getPendingTrades() {
@@ -536,7 +564,7 @@ public class TradeManager {
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     private void persistOffers() {
-        persistence.write(this, "offers", (Map<String, Offer>) new HashMap<>(offers));
+        persistence.write(this, "offers", (Map<String, Offer>) new HashMap<>(openOffers));
     }
 
     private void persistPendingTrades() {
diff --git a/gui/src/main/java/io/bitsquare/trade/TradeMessageService.java b/gui/src/main/java/io/bitsquare/trade/TradeMessageService.java
index 218103b4b2..9255065573 100644
--- a/gui/src/main/java/io/bitsquare/trade/TradeMessageService.java
+++ b/gui/src/main/java/io/bitsquare/trade/TradeMessageService.java
@@ -21,8 +21,8 @@ import io.bitsquare.network.Message;
 import io.bitsquare.network.MessageBroker;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.listeners.GetPeerAddressListener;
-import io.bitsquare.trade.listeners.IncomingMessageListener;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.HandleNewMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 
 import java.security.PublicKey;
 
@@ -32,11 +32,11 @@ public interface TradeMessageService extends MessageBroker {
     
     void setExecutor(Executor executor);
 
-    void sendMessage(Peer peer, Message message, OutgoingMessageListener listener);
+    void sendMessage(Peer peer, Message message, SendMessageListener listener);
 
-    void addIncomingMessageListener(IncomingMessageListener listener);
+    void addHandleNewMessageListener(HandleNewMessageListener listener);
 
-    void removeIncomingMessageListener(IncomingMessageListener listener);
+    void removeHandleNewMessageListener(HandleNewMessageListener listener);
 
     void getPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener);
 }
diff --git a/gui/src/main/java/io/bitsquare/trade/listeners/OutgoingMessageListener.java b/gui/src/main/java/io/bitsquare/trade/listeners/SendMessageListener.java
similarity index 89%
rename from gui/src/main/java/io/bitsquare/trade/listeners/OutgoingMessageListener.java
rename to gui/src/main/java/io/bitsquare/trade/listeners/SendMessageListener.java
index c33e8c63ff..ad7552d3e5 100644
--- a/gui/src/main/java/io/bitsquare/trade/listeners/OutgoingMessageListener.java
+++ b/gui/src/main/java/io/bitsquare/trade/listeners/SendMessageListener.java
@@ -17,8 +17,8 @@
 
 package io.bitsquare.trade.listeners;
 
-public interface OutgoingMessageListener {
-    void onFailed();
+public interface SendMessageListener {
+    void handleFault();
 
-    void onResult();
+    void handleResult();
 }
diff --git a/gui/src/main/java/io/bitsquare/trade/listeners/IncomingMessageListener.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/OfferMessage.java
similarity index 81%
rename from gui/src/main/java/io/bitsquare/trade/listeners/IncomingMessageListener.java
rename to gui/src/main/java/io/bitsquare/trade/protocol/trade/OfferMessage.java
index 52891a2e62..66b4003358 100644
--- a/gui/src/main/java/io/bitsquare/trade/listeners/IncomingMessageListener.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/OfferMessage.java
@@ -15,11 +15,10 @@
  * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package io.bitsquare.trade.listeners;
+package io.bitsquare.trade.protocol.trade;
 
 import io.bitsquare.network.Message;
-import io.bitsquare.network.Peer;
 
-public interface IncomingMessageListener {
-    void onMessage(Message message, Peer sender);
+public interface OfferMessage extends Message {
+    public String getOfferId();
 }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/BuyerAcceptsOfferProtocol.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/BuyerAcceptsOfferProtocol.java
index 5e3036867c..73ace9594f 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/BuyerAcceptsOfferProtocol.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/BuyerAcceptsOfferProtocol.java
@@ -60,9 +60,9 @@ import static io.bitsquare.util.Validator.*;
 /**
  * Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing
  * from the peer.
- * <p>
+ * <p/>
  * This class handles the role of the offerer as the Bitcoin buyer.
- * <p>
+ * <p/>
  * It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
  * Any data from incoming messages need to be validated before further processing.
  */
@@ -159,7 +159,7 @@ public class BuyerAcceptsOfferProtocol {
         checkNotNull(tradeId);
         checkNotNull(offer);
 
-        //TODO use first for now
+        //TODO use default arbitrator for now
         arbitratorPubKey = offer.getArbitrators().get(0).getPubKeyAsHex();
 
         bankAccount = user.getBankAccount(trade.getOffer().getBankAccountId());
@@ -173,10 +173,21 @@ public class BuyerAcceptsOfferProtocol {
     }
 
     public void start() {
-        log.debug("start called " + step++);
+        handleTakeOfferRequest();
+    }
+
+    // 1. HandleTakeOfferRequest
+    // Async
+    // In case of an error: Repeat once, then give up. No rollback activity needed
+    private void handleTakeOfferRequest() {
+        log.debug("handleTakeOfferRequest called " + step++);
         state = State.HandleTakeOfferRequest;
-        HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFault, peer, tradeMessageService,
-                trade.getState(), tradeId);
+        HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onHandleTakeOfferRequestFault, peer, tradeMessageService, trade.getState(), 
+                tradeId);
+    }
+
+    private void onHandleTakeOfferRequestFault(Throwable throwable) {
+        HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFault, peer, tradeMessageService, trade.getState(), tradeId);
     }
 
     public void onResultHandleTakeOfferRequest(boolean takeOfferRequestAccepted) {
@@ -187,6 +198,7 @@ public class BuyerAcceptsOfferProtocol {
             listener.onWaitingForPeerResponse(state);
         }
         else {
+            // Don't use OFFERER_REJECTED as that trade might has been accepted to another taker.
             log.info("Finish here as we have already the offer accepted.");
         }
     }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/messages/RespondToIsOfferAvailableMessage.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/messages/IsOfferAvailableResponseMessage.java
similarity index 75%
rename from gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/messages/RespondToIsOfferAvailableMessage.java
rename to gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/messages/IsOfferAvailableResponseMessage.java
index 3d46141d68..61054dbf00 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/messages/RespondToIsOfferAvailableMessage.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/messages/IsOfferAvailableResponseMessage.java
@@ -17,23 +17,23 @@
 
 package io.bitsquare.trade.protocol.trade.offerer.messages;
 
-import io.bitsquare.trade.protocol.trade.TradeMessage;
+import io.bitsquare.trade.protocol.trade.OfferMessage;
 
 import java.io.Serializable;
 
-public class RespondToIsOfferAvailableMessage implements Serializable, TradeMessage {
+public class IsOfferAvailableResponseMessage implements Serializable, OfferMessage {
     private static final long serialVersionUID = 6177387534187739018L;
-    private final String tradeId;
+    private final String offerId;
     private final boolean isOfferOpen;
 
-    public RespondToIsOfferAvailableMessage(String tradeId, boolean isOfferOpen) {
-        this.tradeId = tradeId;
+    public IsOfferAvailableResponseMessage(String offerId, boolean isOfferOpen) {
+        this.offerId = offerId;
         this.isOfferOpen = isOfferOpen;
     }
 
     @Override
-    public String getTradeId() {
-        return tradeId;
+    public String getOfferId() {
+        return offerId;
     }
 
     public boolean isOfferOpen() {
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/HandleTakeOfferRequest.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/HandleTakeOfferRequest.java
index 03b92613db..3c089bdaf4 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/HandleTakeOfferRequest.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/HandleTakeOfferRequest.java
@@ -17,10 +17,10 @@
 
 package io.bitsquare.trade.protocol.trade.offerer.tasks;
 
-import io.bitsquare.trade.TradeMessageService;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.Trade;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.TradeMessageService;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
 
@@ -32,22 +32,21 @@ public class HandleTakeOfferRequest {
 
     public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, Peer peer,
                            TradeMessageService tradeMessageService, Trade.State tradeState, String tradeId) {
-        log.trace("Run task");
+        log.trace("Run HandleTakeOfferRequest task");
         boolean isTradeIsOpen = tradeState == Trade.State.OPEN;
         if (!isTradeIsOpen) {
             log.warn("Received take offer request but the offer not marked as open anymore.");
         }
-        RespondToTakeOfferRequestMessage tradeMessage =
-                new RespondToTakeOfferRequestMessage(tradeId, isTradeIsOpen);
-        tradeMessageService.sendMessage(peer, tradeMessage, new OutgoingMessageListener() {
+        RespondToTakeOfferRequestMessage tradeMessage = new RespondToTakeOfferRequestMessage(tradeId, isTradeIsOpen);
+        tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
             @Override
-            public void onResult() {
+            public void handleResult() {
                 log.trace("RespondToTakeOfferRequestMessage successfully arrived at peer");
-                resultHandler.onResult(isTradeIsOpen);
+                resultHandler.handleResult(isTradeIsOpen);
             }
 
             @Override
-            public void onFailed() {
+            public void handleFault() {
                 log.error("AcceptTakeOfferRequestMessage  did not arrive at peer");
                 exceptionHandler.handleException(new Exception("AcceptTakeOfferRequestMessage did not arrive at peer"));
             }
@@ -55,6 +54,6 @@ public class HandleTakeOfferRequest {
     }
 
     public interface ResultHandler {
-        void onResult(boolean takeOfferRequestAccepted);
+        void handleResult(boolean takeOfferRequestAccepted);
     }
 }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/IsOfferAvailableResponse.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/IsOfferAvailableResponse.java
new file mode 100644
index 0000000000..ee9189503b
--- /dev/null
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/IsOfferAvailableResponse.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of Bitsquare.
+ *
+ * Bitsquare 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.
+ *
+ * Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package io.bitsquare.trade.protocol.trade.offerer.tasks;
+
+import io.bitsquare.network.Peer;
+import io.bitsquare.trade.TradeMessageService;
+import io.bitsquare.trade.listeners.SendMessageListener;
+import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class IsOfferAvailableResponse {
+    private static final Logger log = LoggerFactory.getLogger(IsOfferAvailableResponse.class);
+
+    public static void run(Peer peer,
+                           TradeMessageService tradeMessageService,
+                           String offerId,
+                           boolean isOfferOpen) {
+        log.trace("Run RespondToIsOfferAvailable task");
+        IsOfferAvailableResponseMessage message = new IsOfferAvailableResponseMessage(offerId, isOfferOpen);
+        tradeMessageService.sendMessage(peer, message, new SendMessageListener() {
+            @Override
+            public void handleResult() {
+                log.trace("RespondToIsOfferAvailableMessage successfully arrived at peer");
+                // Nothing to do. Taker knows now offer available state.
+            }
+
+            @Override
+            public void handleFault() {
+                log.error("RespondToIsOfferAvailableMessage did not arrive at peer");
+                // Ignore that. Taker might have gone offline
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/RequestTakerDepositPayment.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/RequestTakerDepositPayment.java
index aeca92c385..5a6c764562 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/RequestTakerDepositPayment.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/RequestTakerDepositPayment.java
@@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
 
 import io.bitsquare.bank.BankAccount;
 import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.protocol.trade.offerer.messages.RequestTakerDepositPaymentMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
@@ -44,15 +44,15 @@ public class RequestTakerDepositPayment {
         log.trace("Run task");
         RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(
                 tradeId, bankAccount, accountId, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
-        tradeMessageService.sendMessage(peer, tradeMessage, new OutgoingMessageListener() {
+        tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
             @Override
-            public void onResult() {
+            public void handleResult() {
                 log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
                 resultHandler.handleResult();
             }
 
             @Override
-            public void onFailed() {
+            public void handleFault() {
                 log.error("RequestTakerDepositPaymentMessage  did not arrive at peer");
                 exceptionHandler.handleException(new Exception("RequestTakerDepositPaymentMessage did not arrive at " +
                         "peer"));
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendDepositTxIdToTaker.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendDepositTxIdToTaker.java
index 699106e974..8396ce9581 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendDepositTxIdToTaker.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendDepositTxIdToTaker.java
@@ -18,7 +18,7 @@
 package io.bitsquare.trade.protocol.trade.offerer.tasks;
 
 import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
@@ -39,15 +39,15 @@ public class SendDepositTxIdToTaker {
         DepositTxPublishedMessage tradeMessage =
                 new DepositTxPublishedMessage(tradeId, Utils.HEX.encode(depositTransaction.bitcoinSerialize()));
 
-        tradeMessageService.sendMessage(peer, tradeMessage, new OutgoingMessageListener() {
+        tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
             @Override
-            public void onResult() {
+            public void handleResult() {
                 log.trace("DepositTxPublishedMessage successfully arrived at peer");
                 resultHandler.handleResult();
             }
 
             @Override
-            public void onFailed() {
+            public void handleFault() {
                 log.error("DepositTxPublishedMessage  did not arrive at peer");
                 exceptionHandler.handleException(new Exception("DepositTxPublishedMessage did not arrive at peer"));
             }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendSignedPayoutTx.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendSignedPayoutTx.java
index 536e331ffe..356e357864 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendSignedPayoutTx.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendSignedPayoutTx.java
@@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
 
 import io.bitsquare.btc.WalletService;
 import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
@@ -68,15 +68,15 @@ public class SendSignedPayoutTx {
                     takerPaybackAmount,
                     offererPayoutAddress);
 
-            tradeMessageService.sendMessage(peer, tradeMessage, new OutgoingMessageListener() {
+            tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
                 @Override
-                public void onResult() {
+                public void handleResult() {
                     log.trace("BankTransferInitedMessage successfully arrived at peer");
                     resultHandler.handleResult();
                 }
 
                 @Override
-                public void onFailed() {
+                public void handleFault() {
                     log.error("BankTransferInitedMessage did not arrive at peer");
                     exceptionHandler.handleException(new Exception("BankTransferInitedMessage did not arrive at peer"));
 
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/RequestIsOfferAvailableProtocol.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/RequestIsOfferAvailableProtocol.java
new file mode 100644
index 0000000000..832bb0f723
--- /dev/null
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/RequestIsOfferAvailableProtocol.java
@@ -0,0 +1,116 @@
+/*
+ * This file is part of Bitsquare.
+ *
+ * Bitsquare 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.
+ *
+ * Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package io.bitsquare.trade.protocol.trade.taker;
+
+import io.bitsquare.network.Peer;
+import io.bitsquare.offer.Offer;
+import io.bitsquare.trade.TradeMessageService;
+import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
+import io.bitsquare.trade.protocol.trade.taker.tasks.GetPeerAddress;
+import io.bitsquare.trade.protocol.trade.taker.tasks.RequestIsOfferAvailable;
+
+import java.security.PublicKey;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing
+ * from the peer.
+ * That class handles the role of the taker as the Bitcoin seller.
+ * It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
+ * Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
+ */
+public class RequestIsOfferAvailableProtocol {
+    private static final Logger log = LoggerFactory.getLogger(RequestIsOfferAvailableProtocol.class);
+
+
+    // provided data
+    private final Offer offer;
+    private final TradeMessageService tradeMessageService;
+
+    // derived
+    private final String offerId;
+    private final PublicKey offererMessagePublicKey;
+
+    // written/read by task
+    private Peer peer;
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////////
+    // Constructor
+    ///////////////////////////////////////////////////////////////////////////////////////////
+
+    public RequestIsOfferAvailableProtocol(Offer offer,
+                                           TradeMessageService tradeMessageService) {
+        this.offer = offer;
+        this.tradeMessageService = tradeMessageService;
+        offerId = offer.getId();
+        offererMessagePublicKey = offer.getMessagePublicKey();
+    }
+
+    public void start() {
+        getPeerAddress();
+    }
+
+    // 1. GetPeerAddress
+    // Async
+    // In case of an error: Repeat once, then give up. 
+    private void getPeerAddress() {
+        log.debug("getPeerAddress called");
+        GetPeerAddress.run(this::onResultGetPeerAddress, this::onGetPeerAddressFault, tradeMessageService, offererMessagePublicKey);
+    }
+
+    private void onGetPeerAddressFault(String errorMessage) {
+        GetPeerAddress.run(this::onResultGetPeerAddress, this::handleErrorMessage, tradeMessageService, offererMessagePublicKey);
+    }
+
+
+    // 2. RequestTakeOffer
+    // Async
+    // In case of an error: Repeat once, then give up.
+    public void onResultGetPeerAddress(Peer peer) {
+        log.debug("onResultGetPeerAddress called");
+        this.peer = peer;
+
+        RequestIsOfferAvailable.run(this::onRequestIsOfferAvailableFault, peer, tradeMessageService, offerId);
+    }
+
+    private void onRequestIsOfferAvailableFault(String errorMessage) {
+        RequestIsOfferAvailable.run(this::handleErrorMessage, peer, tradeMessageService, offerId);
+    }
+
+    // generic
+    private void handleErrorMessage(String errorMessage) {
+        offer.setState(Offer.State.OFFER_NOT_AVAILABLE);
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////////
+    // Incoming message from peer
+    ///////////////////////////////////////////////////////////////////////////////////////////
+
+    public void handleIsOfferAvailableResponseMessage(IsOfferAvailableResponseMessage offerMessage) {
+        if (offer.getState() != Offer.State.OFFER_REMOVED) {
+            if (offerMessage.isOfferOpen())
+                offer.setState(Offer.State.OFFER_AVAILABLE);
+            else
+                offer.setState(Offer.State.OFFER_NOT_AVAILABLE);
+        }
+    }
+}
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/SellerTakesOfferProtocol.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/SellerTakesOfferProtocol.java
index 6dafa3dfc9..2989b365f5 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/SellerTakesOfferProtocol.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/SellerTakesOfferProtocol.java
@@ -100,7 +100,7 @@ public class SellerTakesOfferProtocol {
     private final Coin tradeAmount;
     private final String pubKeyForThatTrade;
     private final ECKey accountKey;
-    private final PublicKey peersMessagePublicKey;
+    private final PublicKey offererMessagePublicKey;
     private final Coin securityDeposit;
     private final String arbitratorPubKey;
 
@@ -120,6 +120,7 @@ public class SellerTakesOfferProtocol {
     private Coin offererPaybackAmount;
     private Coin takerPaybackAmount;
     private String offererPayoutAddress;
+    private int repeatCounter = 0;
 
 
     // state
@@ -152,7 +153,7 @@ public class SellerTakesOfferProtocol {
         //TODO use 1. for now
         arbitratorPubKey = trade.getOffer().getArbitrators().get(0).getPubKeyAsHex();
 
-        peersMessagePublicKey = offer.getMessagePublicKey();
+        offererMessagePublicKey = offer.getMessagePublicKey();
 
         bankAccount = user.getCurrentBankAccount().get();
         accountId = user.getAccountId();
@@ -164,20 +165,37 @@ public class SellerTakesOfferProtocol {
         state = State.Init;
     }
 
-    // 1. GetPeerAddress
-    // Async
-    // In case of an error: No rollback activity needed
     public void start() {
-        log.debug("start called " + step++);
-        state = State.GetPeerAddress;
-        GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, tradeMessageService, peersMessagePublicKey);
+        getPeerAddress();
     }
 
+    // 1. GetPeerAddress
+    // Async
+    // In case of an error: Repeat once, then give up. No rollback activity needed
+    private void getPeerAddress() {
+        log.debug("getPeerAddress called " + step++);
+        state = State.GetPeerAddress;
+        GetPeerAddress.run(this::onResultGetPeerAddress, this::onGetPeerAddressFault, tradeMessageService, offererMessagePublicKey);
+    }
+
+    private void onGetPeerAddressFault(String errorMessage) {
+        log.debug("Run getPeerAddress again after onGetPeerAddressFault" + step);
+        GetPeerAddress.run(this::onResultGetPeerAddress, this::onErrorMessage, tradeMessageService, offererMessagePublicKey);
+    }
+
+    // 2. RequestTakeOffer
+    // Async
+    // In case of an error: Repeat once, then give up. No rollback activity needed
     public void onResultGetPeerAddress(Peer peer) {
         log.debug("onResultGetPeerAddress called " + step++);
         this.peer = peer;
 
         state = State.RequestTakeOffer;
+        RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onRequestTakeOfferFault, peer, tradeMessageService, tradeId);
+    }
+
+    private void onRequestTakeOfferFault(Throwable throwable) {
+        log.debug("Run getPeerAddress again after onGetPeerAddressFault" + step);
         RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, peer, tradeMessageService, tradeId);
     }
 
@@ -191,6 +209,9 @@ public class SellerTakesOfferProtocol {
     // Incoming message from peer
     ///////////////////////////////////////////////////////////////////////////////////////////
 
+    // 3. PayTakeOfferFee
+    // Async
+    // In case of an error: Repeat once, then give up. No rollback activity needed
     public void onRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message) {
         log.debug("onRespondToTakeOfferRequestMessage called " + step++);
         log.debug("state " + state);
@@ -266,7 +287,7 @@ public class SellerTakesOfferProtocol {
                 takeOfferFeeTxId,
                 accountId,
                 bankAccount,
-                peersMessagePublicKey,
+                offererMessagePublicKey,
                 messagePublicKey,
                 peersAccountId,
                 peersBankAccount,
@@ -415,4 +436,8 @@ public class SellerTakesOfferProtocol {
         listener.onFault(throwable, state);
     }
 
+    private void onErrorMessage(String errorMessage) {
+        listener.onFault(new Exception(errorMessage), state);
+    }
+
 }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/messages/RequestIsOfferAvailableMessage.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/messages/RequestIsOfferAvailableMessage.java
index 6740195035..3d759c2f74 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/messages/RequestIsOfferAvailableMessage.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/messages/RequestIsOfferAvailableMessage.java
@@ -17,22 +17,22 @@
 
 package io.bitsquare.trade.protocol.trade.taker.messages;
 
-import io.bitsquare.trade.protocol.trade.TradeMessage;
+import io.bitsquare.trade.protocol.trade.OfferMessage;
 
 import java.io.Serializable;
 
 // That msg is used to ping the offerer if he is online and if the offer is still available
-public class RequestIsOfferAvailableMessage implements Serializable, TradeMessage {
+public class RequestIsOfferAvailableMessage implements Serializable, OfferMessage {
     private static final long serialVersionUID = 4630151440192191798L;
-    private final String tradeId;
+    private final String offerId;
 
-    public RequestIsOfferAvailableMessage(String tradeId) {
-        this.tradeId = tradeId;
+    public RequestIsOfferAvailableMessage(String offerId) {
+        this.offerId = offerId;
     }
 
     @Override
-    public String getTradeId() {
-        return tradeId;
+    public String getOfferId() {
+        return offerId;
     }
 
 
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/GetPeerAddress.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/GetPeerAddress.java
index d3cc279ae7..885c3a10ef 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/GetPeerAddress.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/GetPeerAddress.java
@@ -20,7 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.TradeMessageService;
 import io.bitsquare.trade.listeners.GetPeerAddressListener;
-import io.bitsquare.util.handlers.ExceptionHandler;
+import io.bitsquare.util.handlers.ErrorMessageHandler;
 
 import java.security.PublicKey;
 
@@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory;
 public class GetPeerAddress {
     private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
     
-    public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler,
+    public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler,
                            TradeMessageService tradeMessageService, PublicKey messagePublicKey) {
         log.trace("Run GetPeerAddress task");
         tradeMessageService.getPeerAddress(messagePublicKey, new GetPeerAddressListener() {
@@ -43,7 +43,7 @@ public class GetPeerAddress {
             @Override
             public void onFailed() {
                 log.error("Lookup for peer address failed.");
-                exceptionHandler.handleException(new Exception("Lookup for peer address failed."));
+                errorMessageHandler.handleErrorMessage("Lookup for peer address failed.");
             }
         });
     }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestIsOfferAvailable.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestIsOfferAvailable.java
new file mode 100644
index 0000000000..59ce87902b
--- /dev/null
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestIsOfferAvailable.java
@@ -0,0 +1,52 @@
+/*
+ * This file is part of Bitsquare.
+ *
+ * Bitsquare 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.
+ *
+ * Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package io.bitsquare.trade.protocol.trade.taker.tasks;
+
+import io.bitsquare.network.Peer;
+import io.bitsquare.trade.TradeMessageService;
+import io.bitsquare.trade.listeners.SendMessageListener;
+import io.bitsquare.trade.protocol.trade.taker.messages.RequestIsOfferAvailableMessage;
+import io.bitsquare.util.handlers.ErrorMessageHandler;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RequestIsOfferAvailable {
+    private static final Logger log = LoggerFactory.getLogger(RequestIsOfferAvailable.class);
+
+    public static void run(ErrorMessageHandler errorMessageHandler,
+                           Peer peer, TradeMessageService tradeMessageService, String offerId) {
+        log.trace("Run RequestIsOfferAvailable task");
+
+        tradeMessageService.sendMessage(peer, new RequestIsOfferAvailableMessage(offerId),
+                new SendMessageListener() {
+                    @Override
+                    public void handleResult() {
+                        log.trace("RequestIsOfferAvailableMessage successfully arrived at peer");
+                        // nothing to do
+                    }
+
+                    @Override
+                    public void handleFault() {
+                        log.error("RequestIsOfferAvailableMessage did not arrive at peer");
+                        errorMessageHandler.handleErrorMessage("RequestIsOfferAvailableMessage did not arrive at peer");
+                    }
+                });
+    }
+}
+
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestTakeOffer.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestTakeOffer.java
index 6ea91d8287..13cfc4c119 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestTakeOffer.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/RequestTakeOffer.java
@@ -18,7 +18,7 @@
 package io.bitsquare.trade.protocol.trade.taker.tasks;
 
 import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
@@ -32,20 +32,19 @@ public class RequestTakeOffer {
 
     public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, Peer peer,
                            TradeMessageService tradeMessageService, String tradeId) {
-        log.trace("Run task");
+        log.trace("Run RequestTakeOffer task");
         tradeMessageService.sendMessage(peer, new RequestTakeOfferMessage(tradeId),
-                new OutgoingMessageListener() {
+                new SendMessageListener() {
                     @Override
-                    public void onResult() {
+                    public void handleResult() {
                         log.trace("RequestTakeOfferMessage successfully arrived at peer");
                         resultHandler.handleResult();
                     }
 
                     @Override
-                    public void onFailed() {
-                        log.error("RequestTakeOfferMessage  did not arrive at peer");
-                        exceptionHandler.handleException(new Exception("RequestTakeOfferMessage did not arrive at " +
-                                "peer"));
+                    public void handleFault() {
+                        log.error("RequestTakeOfferMessage did not arrive at peer");
+                        exceptionHandler.handleException(new Exception("RequestTakeOfferMessage did not arrive at peer"));
                     }
                 });
     }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendPayoutTxToOfferer.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendPayoutTxToOfferer.java
index db10ceed58..6268bb6c16 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendPayoutTxToOfferer.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendPayoutTxToOfferer.java
@@ -18,7 +18,7 @@
 package io.bitsquare.trade.protocol.trade.taker.tasks;
 
 import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
@@ -34,15 +34,15 @@ public class SendPayoutTxToOfferer {
                            TradeMessageService tradeMessageService, String tradeId, String payoutTxAsHex) {
         log.trace("Run task");
         PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex);
-        tradeMessageService.sendMessage(peer, tradeMessage, new OutgoingMessageListener() {
+        tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
             @Override
-            public void onResult() {
+            public void handleResult() {
                 log.trace("PayoutTxPublishedMessage successfully arrived at peer");
                 resultHandler.handleResult();
             }
 
             @Override
-            public void onFailed() {
+            public void handleFault() {
                 log.error("PayoutTxPublishedMessage  did not arrive at peer");
                 exceptionHandler.handleException(new Exception("PayoutTxPublishedMessage did not arrive at peer"));
             }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendSignedTakerDepositTxAsHex.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendSignedTakerDepositTxAsHex.java
index 2c02530cae..9d169c9966 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendSignedTakerDepositTxAsHex.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendSignedTakerDepositTxAsHex.java
@@ -20,7 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
 import io.bitsquare.bank.BankAccount;
 import io.bitsquare.btc.WalletService;
 import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
@@ -68,15 +68,15 @@ public class SendSignedTakerDepositTxAsHex {
                 walletService.getAddressInfoByTradeID(tradeId).getAddressString(),
                 takerTxOutIndex,
                 offererTxOutIndex);
-        tradeMessageService.sendMessage(peer, tradeMessage, new OutgoingMessageListener() {
+        tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
             @Override
-            public void onResult() {
+            public void handleResult() {
                 log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
                 resultHandler.handleResult();
             }
 
             @Override
-            public void onFailed() {
+            public void handleFault() {
                 log.error("RequestOffererDepositPublicationMessage  did not arrive at peer");
                 exceptionHandler.handleException(
                         new Exception("RequestOffererDepositPublicationMessage did not arrive at peer"));
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendTakeOfferFeePayedTxId.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendTakeOfferFeePayedTxId.java
index 4c605a1893..7ec8de4296 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendTakeOfferFeePayedTxId.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SendTakeOfferFeePayedTxId.java
@@ -18,7 +18,7 @@
 package io.bitsquare.trade.protocol.trade.taker.tasks;
 
 import io.bitsquare.trade.TradeMessageService;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
 import io.bitsquare.util.handlers.ExceptionHandler;
@@ -44,15 +44,15 @@ public class SendTakeOfferFeePayedTxId {
         TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId, takeOfferFeeTxId, tradeAmount,
                 pubKeyForThatTradeAsHex);
 
-        tradeMessageService.sendMessage(peer, msg, new OutgoingMessageListener() {
+        tradeMessageService.sendMessage(peer, msg, new SendMessageListener() {
             @Override
-            public void onResult() {
+            public void handleResult() {
                 log.trace("TakeOfferFeePayedMessage successfully arrived at peer");
                 resultHandler.handleResult();
             }
 
             @Override
-            public void onFailed() {
+            public void handleFault() {
                 log.error("TakeOfferFeePayedMessage  did not arrive at peer");
                 exceptionHandler.handleException(new Exception("TakeOfferFeePayedMessage did not arrive at peer"));
             }
diff --git a/gui/src/main/java/io/bitsquare/trade/tomp2p/TomP2PTradeMessageService.java b/gui/src/main/java/io/bitsquare/trade/tomp2p/TomP2PTradeMessageService.java
index 3937886c76..f6f990c992 100644
--- a/gui/src/main/java/io/bitsquare/trade/tomp2p/TomP2PTradeMessageService.java
+++ b/gui/src/main/java/io/bitsquare/trade/tomp2p/TomP2PTradeMessageService.java
@@ -23,8 +23,8 @@ import io.bitsquare.network.tomp2p.TomP2PNode;
 import io.bitsquare.network.tomp2p.TomP2PPeer;
 import io.bitsquare.trade.TradeMessageService;
 import io.bitsquare.trade.listeners.GetPeerAddressListener;
-import io.bitsquare.trade.listeners.IncomingMessageListener;
-import io.bitsquare.trade.listeners.OutgoingMessageListener;
+import io.bitsquare.trade.listeners.HandleNewMessageListener;
+import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.user.User;
 
 import java.security.PublicKey;
@@ -58,7 +58,7 @@ public class TomP2PTradeMessageService implements TradeMessageService {
 
     private final TomP2PNode tomP2PNode;
     private final User user;
-    private final List<IncomingMessageListener> incomingMessageListeners = new ArrayList<>();
+    private final List<HandleNewMessageListener> handleNewMessageListeners = new ArrayList<>();
     private Executor executor;
 
 
@@ -70,8 +70,8 @@ public class TomP2PTradeMessageService implements TradeMessageService {
         this.user = user;
         this.tomP2PNode = tomP2PNode;
     }
-    
-    
+
+
     public void setExecutor(Executor executor) {
         this.executor = executor;
     }
@@ -101,11 +101,10 @@ public class TomP2PTradeMessageService implements TradeMessageService {
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////
-    // Trade process
+    // Trade messages
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    public void sendMessage(Peer peer, Message message,
-                            OutgoingMessageListener listener) {
+    public void sendMessage(Peer peer, Message message, SendMessageListener listener) {
         if (!(peer instanceof TomP2PPeer)) {
             throw new IllegalArgumentException("peer must be of type TomP2PPeer");
         }
@@ -114,17 +113,17 @@ public class TomP2PTradeMessageService implements TradeMessageService {
             @Override
             public void operationComplete(BaseFuture future) throws Exception {
                 if (future.isSuccess()) {
-                    executor.execute(listener::onResult);
+                    executor.execute(listener::handleResult);
                 }
                 else {
                     log.error("sendMessage failed with reason " + futureDirect.failedReason());
-                    executor.execute(listener::onFailed);
+                    executor.execute(listener::handleFault);
                 }
             }
 
             @Override
             public void exceptionCaught(Throwable t) throws Exception {
-                executor.execute(listener::onFailed);
+                executor.execute(listener::handleFault);
             }
         });
     }
@@ -134,12 +133,12 @@ public class TomP2PTradeMessageService implements TradeMessageService {
     // Event Listeners
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    public void addIncomingMessageListener(IncomingMessageListener listener) {
-        incomingMessageListeners.add(listener);
+    public void addHandleNewMessageListener(HandleNewMessageListener listener) {
+        handleNewMessageListeners.add(listener);
     }
 
-    public void removeIncomingMessageListener(IncomingMessageListener listener) {
-        incomingMessageListeners.remove(listener);
+    public void removeHandleNewMessageListener(HandleNewMessageListener listener) {
+        handleNewMessageListeners.remove(listener);
     }
 
 
@@ -149,9 +148,9 @@ public class TomP2PTradeMessageService implements TradeMessageService {
 
     @Override
     public void handleMessage(Object message, Peer sender) {
-        if (message instanceof Message) {
-            executor.execute(() -> incomingMessageListeners.stream().forEach(e ->
-                    e.onMessage((Message) message, sender)));
+        if (message instanceof Message && sender instanceof TomP2PPeer) {
+            executor.execute(() -> handleNewMessageListeners.stream().forEach(e ->
+                    e.handleMessage((Message) message, sender)));
         }
     }
 }