From 033709f2880a00c0e5df96af179b9fc9b369b155 Mon Sep 17 00:00:00 2001
From: Manfred Karrer <mk@nucleo.io>
Date: Tue, 10 Mar 2015 23:29:28 +0100
Subject: [PATCH] Move fee verification task to end

---
 .../java/io/bitsquare/btc/WalletService.java  |   1 -
 .../java/io/bitsquare/trade/TradeManager.java |  47 +++-
 .../SellerTakesOfferProtocolListener.java     |   2 +-
 .../offerer/BuyerAcceptsOfferProtocol.java    | 247 ++++++++++--------
 .../trade/offerer/tasks/CreateDepositTx.java  |  10 +-
 ...ava => SendBankTransferInitedMessage.java} |  40 +--
 .../offerer/tasks/SendDepositTxIdToTaker.java |   4 +-
 ...etupListenerForBlockChainConfirmation.java |   1 +
 .../trade/offerer/tasks/SignPayoutTx.java     |  72 +++++
 .../tasks/VerifyTakeOfferFeePayment.java      |   7 +-
 .../trade/taker/SellerTakesOfferProtocol.java | 197 ++++++++------
 .../taker/tasks/SendPayoutTxToOfferer.java    |  10 +-
 .../taker/tasks/SignAndPublishPayoutTx.java   |   5 +-
 .../taker/tasks/VerifyOfferFeePayment.java}   |  20 +-
 14 files changed, 398 insertions(+), 265 deletions(-)
 rename gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/{SendSignedPayoutTx.java => SendBankTransferInitedMessage.java} (59%)
 create mode 100644 gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SignPayoutTx.java
 rename gui/src/main/java/io/bitsquare/trade/{TradeMessage.java => protocol/trade/taker/tasks/VerifyOfferFeePayment.java} (52%)

diff --git a/gui/src/main/java/io/bitsquare/btc/WalletService.java b/gui/src/main/java/io/bitsquare/btc/WalletService.java
index e96bcb160b..d37f6c40e0 100644
--- a/gui/src/main/java/io/bitsquare/btc/WalletService.java
+++ b/gui/src/main/java/io/bitsquare/btc/WalletService.java
@@ -611,7 +611,6 @@ public class WalletService {
 
     // 1. step: deposit tx
     // Offerer creates the 2of3 multiSig deposit tx with his unsigned input and change output
-
     public Transaction offererCreatesMSTxAndAddPayment(Coin offererInputAmount,
                                                        String offererPubKey,
                                                        String takerPubKey,
diff --git a/gui/src/main/java/io/bitsquare/trade/TradeManager.java b/gui/src/main/java/io/bitsquare/trade/TradeManager.java
index 43d941a893..de7d6abb01 100644
--- a/gui/src/main/java/io/bitsquare/trade/TradeManager.java
+++ b/gui/src/main/java/io/bitsquare/trade/TradeManager.java
@@ -281,12 +281,10 @@ public class TradeManager {
 
                         @Override
                         public void onDepositTxPublished(Transaction depositTx) {
-                            trade.setDepositTx(depositTx);
-                            trade.setState(Trade.State.DEPOSIT_PUBLISHED);
                             persistPendingTrades();
-                            log.trace("trading onDepositTxPublishedMessage " + depositTx.getHashAsString());
                         }
 
+                        // TODO should be removed
                         @Override
                         public void onDepositTxConfirmedInBlockchain() {
                             log.trace("trading onDepositTxConfirmedInBlockchain");
@@ -311,6 +309,36 @@ public class TradeManager {
                                 case RespondToTakeOfferRequest:
                                     removeFailedTrade(trade);
                                     break;
+                                case ValidateTakeOfferFeePayedMessage:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case CreateDepositTx:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case SendTakerDepositPaymentRequest:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case ValidateRequestOffererPublishDepositTxMessage:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case VerifyTakerAccount:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case VerifyAndSignContract:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case SignAndPublishDepositTx:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case SignAndPublishDepositTxResulted:
+                                    removeFailedTrade(trade);
+                                    break;
+                                case SendSignedPayoutTx:
+                                    removeFailedTrade(trade);
+                                    break;
+                                default:
+                                    log.error("Unhandled state: " + state);
+                                    break;
                             }
                         }
                     });
@@ -347,9 +375,7 @@ public class TradeManager {
             }
 
             @Override
-            public void onDepositTxPublished(Transaction depositTx) {
-                trade.setDepositTx(depositTx);
-                trade.setState(Trade.State.DEPOSIT_PUBLISHED);
+            public void onDepositTxPublished() {
                 persistPendingTrades();
             }
 
@@ -378,12 +404,19 @@ public class TradeManager {
                     case RequestTakeOffer:
                         removeFailedTrade(trade);
                         break;
+                    case ValidateRespondToTakeOfferRequestMessage:
+                        // TODO might need further inspection. Removal could be used for sabotage.
+                        //removeFailedTrade(trade);
+                        break;
                     case PayTakeOfferFee:
                         removeFailedTrade(trade);
                         break;
                     case SendTakeOfferFeePayedMessage:
                         removeFailedTrade(trade);
                         break;
+                    case ValidateTakerDepositPaymentRequestMessage:
+                        removeFailedTrade(trade);
+                        break;
 
 
                 }
@@ -410,7 +443,7 @@ public class TradeManager {
     // Also we don't support yet offline messaging (mail box)
     public void fiatPaymentStarted(String tradeId) {
         if (offererAsBuyerProtocolMap.get(tradeId) != null) {
-            offererAsBuyerProtocolMap.get(tradeId).handleUIEventBankTransferInited();
+            offererAsBuyerProtocolMap.get(tradeId).handleUIEventBankTransferStarted();
             pendingTrades.get(tradeId).setState(Trade.State.PAYMENT_STARTED);
             persistPendingTrades();
         }
diff --git a/gui/src/main/java/io/bitsquare/trade/listeners/SellerTakesOfferProtocolListener.java b/gui/src/main/java/io/bitsquare/trade/listeners/SellerTakesOfferProtocolListener.java
index 931081cb7b..6055c3e3c8 100644
--- a/gui/src/main/java/io/bitsquare/trade/listeners/SellerTakesOfferProtocolListener.java
+++ b/gui/src/main/java/io/bitsquare/trade/listeners/SellerTakesOfferProtocolListener.java
@@ -23,7 +23,7 @@ import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol;
 import org.bitcoinj.core.Transaction;
 
 public interface SellerTakesOfferProtocolListener {
-    void onDepositTxPublished(Transaction depositTx);
+    void onDepositTxPublished();
 
     void onBankTransferInited(String tradeId);
 
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 8970d9b014..8d50903640 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
@@ -19,7 +19,6 @@ package io.bitsquare.trade.protocol.trade.offerer;
 
 import io.bitsquare.bank.BankAccount;
 import io.bitsquare.btc.BlockChainService;
-import io.bitsquare.btc.FeePolicy;
 import io.bitsquare.btc.WalletService;
 import io.bitsquare.crypto.SignatureService;
 import io.bitsquare.network.Peer;
@@ -30,12 +29,14 @@ import io.bitsquare.trade.TradeMessageService;
 import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateDepositTx;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
+import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferInitedMessage;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker;
-import io.bitsquare.trade.protocol.trade.offerer.tasks.SendSignedPayoutTx;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.SendTakerDepositPaymentRequest;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx;
+import io.bitsquare.trade.protocol.trade.offerer.tasks.SignPayoutTx;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract;
+import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
 import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
 import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
 import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
@@ -49,8 +50,6 @@ import org.bitcoinj.core.Utils;
 
 import java.security.PublicKey;
 
-import org.jetbrains.annotations.NotNull;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -74,22 +73,19 @@ public class BuyerAcceptsOfferProtocol {
         Init,
         RespondToTakeOfferRequest,
 
-        handleTakeOfferFeePayedMessage,
-       /* VerifyTakeOfferFeePayment,*/
+        /* VerifyTakeOfferFeePayment,*/
+        ValidateTakeOfferFeePayedMessage,
         CreateDepositTx,
-        RequestTakerDepositPayment,
+        SendTakerDepositPaymentRequest,
 
-        handleRequestOffererPublishDepositTxMessage,
+        ValidateRequestOffererPublishDepositTxMessage,
         VerifyTakerAccount,
         VerifyAndSignContract,
         SignAndPublishDepositTx,
-        SendDepositTxIdToTaker,
-        SetupListenerForBlockChainConfirmation,
+        SignAndPublishDepositTxResulted,
 
-        handleUIEventBankTransferInited,
-        SendSignedPayoutTx,
-
-        handlePayoutTxPublishedMessage
+        SignPayoutTx,
+        SendSignedPayoutTx
     }
 
     // provided
@@ -203,46 +199,46 @@ public class BuyerAcceptsOfferProtocol {
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     // 8. handleTakeOfferFeePayedMessage
-    public void handleTakeOfferFeePayedMessage(@NotNull TakeOfferFeePayedMessage message) {
+    public void handleTakeOfferFeePayedMessage(TakeOfferFeePayedMessage message) {
         log.debug("handleTakeOfferFeePayedMessage called: state = " + state);
 
         // validation
-        checkState(state == State.RespondToTakeOfferRequest);
-        checkTradeId(tradeId, message);
-        String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
-        Coin tradeAmount = positiveCoinOf(nonZeroCoinOf(message.getTradeAmount()));
-        String tradePubKeyAsHex = nonEmptyStringOf(message.getTakerPubKeyAsHex());
+        try {
+            checkState(state == State.RespondToTakeOfferRequest);
+            state = State.ValidateTakeOfferFeePayedMessage;
+            checkTradeId(tradeId, message);
+            String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
+            Coin tradeAmount = positiveCoinOf(nonZeroCoinOf(message.getTradeAmount()));
+            String tradePubKeyAsHex = nonEmptyStringOf(message.getTakerPubKeyAsHex());
 
-        // apply new state
-        state = State.handleTakeOfferFeePayedMessage;
-        this.takeOfferFeeTxId = takeOfferFeeTxId;
-        this.tradePubKeyAsHex = tradePubKeyAsHex;
-        trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
-        trade.setTradeAmount(tradeAmount);
+            // apply new state
+            this.takeOfferFeeTxId = takeOfferFeeTxId;
+            this.tradePubKeyAsHex = tradePubKeyAsHex;
+            trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
+            trade.setTradeAmount(tradeAmount);
 
-        // next task
-        createDepositTx();
+            // next task
+            createDepositTx();
+        } catch (Throwable t) {
+            handleValidationFault(t);
+        }
     }
 
     // 9. CreateDepositTx
     private void createDepositTx() {
         log.debug("handleVerifyTakeOfferFeePaymentResult called: state = " + state);
-        checkState(state == State.handleTakeOfferFeePayedMessage);
-        Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
         state = State.CreateDepositTx;
-        CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, tradeId, offererInputAmount,
-                tradePubKeyAsHex, arbitratorPubKey);
+        CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, trade, tradePubKeyAsHex, arbitratorPubKey);
     }
 
-    // 4. RequestTakerDepositPayment
+    // 10. RequestTakerDepositPayment
     private void handleCreateDepositTxResult(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex) {
         log.debug("handleCreateDepositTxResult called: state = " + state);
-        checkState(state == State.CreateDepositTx);
 
         this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
         this.offererTxOutIndex = offererTxOutIndex;
 
-        state = State.RequestTakerDepositPayment;
+        state = State.SendTakerDepositPaymentRequest;
         SendTakerDepositPaymentRequest.run(this::handleErrorMessage,
                 peer,
                 tradeMessageService,
@@ -259,43 +255,52 @@ public class BuyerAcceptsOfferProtocol {
     // Incoming message from peer
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    // 5. VerifyTakerAccount
+    // 16. VerifyTakerAccount
     public void handleRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message) {
         log.debug("handleRequestOffererPublishDepositTxMessage called: state = " + state);
-        log.debug("state " + state);
 
-        // validation
-        checkState(state == State.RequestTakerDepositPayment);
-        checkTradeId(tradeId, message);
-        String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
-        String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
-        BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
-        PublicKey peersMessagePublicKey = checkNotNull(message.getTakerMessagePublicKey());
-        String peersContractAsJson = nonEmptyStringOf(message.getTakerContractAsJson());
-        String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
-        String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
-        String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
-        long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
 
-        // apply new state
-        state = State.handleRequestOffererPublishDepositTxMessage;
-        this.peersPayoutAddress = peersPayoutAddress;
-        this.peersAccountId = peersAccountId;
-        this.peersBankAccount = peersBankAccount;
-        this.peersMessagePublicKey = peersMessagePublicKey;
-        this.peersContractAsJson = peersContractAsJson;
-        this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
-        this.txConnOutAsHex = txConnOutAsHex;
-        this.txScriptSigAsHex = txScriptSigAsHex;
-        this.takerTxOutIndex = takerTxOutIndex;
+        try {
+            // validation
+            checkState(state == State.SendTakerDepositPaymentRequest);
+            state = State.ValidateRequestOffererPublishDepositTxMessage;
+            checkTradeId(tradeId, message);
+            String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
+            String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
+            BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
+            PublicKey peersMessagePublicKey = checkNotNull(message.getTakerMessagePublicKey());
+            String peersContractAsJson = nonEmptyStringOf(message.getTakerContractAsJson());
+            String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
+            String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
+            String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
+            long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
 
-        // next task
+            // apply new state
+            this.peersPayoutAddress = peersPayoutAddress;
+            this.peersAccountId = peersAccountId;
+            this.peersBankAccount = peersBankAccount;
+            this.peersMessagePublicKey = peersMessagePublicKey;
+            this.peersContractAsJson = peersContractAsJson;
+            this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
+            this.txConnOutAsHex = txConnOutAsHex;
+            this.txScriptSigAsHex = txScriptSigAsHex;
+            this.takerTxOutIndex = takerTxOutIndex;
+
+            // next task
+            verifyTakerAccount();
+        } catch (Throwable t) {
+            handleValidationFault(t);
+        }
+    }
+
+    // 17. VerifyTakerAccount
+    private void verifyTakerAccount() {
         state = State.VerifyTakerAccount;
         VerifyTakerAccount.run(this::handleVerifyTakerAccountResult, this::handleFault, blockChainService,
                 this.peersAccountId, this.peersBankAccount);
     }
 
-    // 6. VerifyAndSignContract
+    // 18. VerifyAndSignContract
     private void handleVerifyTakerAccountResult() {
         log.debug("handleVerifyTakerAccountResult called: state = " + state);
 
@@ -317,7 +322,7 @@ public class BuyerAcceptsOfferProtocol {
                 accountKey);
     }
 
-    // 7. SignAndPublishDepositTx
+    // 19. SignAndPublishDepositTx
     private void handleVerifyAndSignContractResult(Contract contract, String contractAsJson, String signature) {
         log.debug("handleVerifyAndSignContractResult called: state = " + state);
 
@@ -336,66 +341,47 @@ public class BuyerAcceptsOfferProtocol {
                 takerTxOutIndex);
     }
 
-    // 8. SendDepositTxIdToTaker
     private void handleSignAndPublishDepositTxResult(Transaction depositTransaction) {
         log.debug("handleSignAndPublishDepositTxResult called: state = " + state);
 
+        state = State.SignAndPublishDepositTxResulted;
+        trade.setDepositTx(depositTransaction);
+        trade.setState(Trade.State.DEPOSIT_PUBLISHED);
         listener.onDepositTxPublished(depositTransaction);
 
-        state = State.SendDepositTxIdToTaker;
-        SendDepositTxIdToTaker.run(this::handleSendDepositTxIdToTakerResult, this::handleErrorMessage, peer, tradeMessageService,
-                tradeId, depositTransaction);
+        sendDepositTxIdToTaker(depositTransaction);
+        setupListenerForBlockChainConfirmation();
     }
 
-    private void handleSendDepositTxIdToTakerResult() {
-        log.debug("handleSendDepositTxIdToTakerResult called: state = " + state);
+    // 20a. SendDepositTxIdToTaker
+    private void sendDepositTxIdToTaker(Transaction depositTransaction) {
+        log.debug("sendDepositTxIdToTaker called: state = " + state);
+        SendDepositTxIdToTaker.run(this::handleErrorMessage, peer, tradeMessageService, tradeId, depositTransaction);
+    }
 
-        state = State.SetupListenerForBlockChainConfirmation;
+    // TODO remove
+    // 20b. SetupListenerForBlockChainConfirmation
+    private void setupListenerForBlockChainConfirmation() {
+        log.debug("setupListenerForBlockChainConfirmation called: state = " + state);
         SetupListenerForBlockChainConfirmation.run(trade.getDepositTx(), listener);
     }
 
-    /*
-     // 9. VerifyTakeOfferFeePayment
-    private void verifyTakeOfferFeePayment() {
-        state = State.VerifyTakeOfferFeePayment;
-        VerifyTakeOfferFeePayment.run(this::handleVerifyTakeOfferFeePaymentResult, this::handleFault, walletService, this.takeOfferFeeTxId);
-    }
-
-    // 10. CreateDepositTx
-    private void handleVerifyTakeOfferFeePaymentResult() {
-        log.debug("handleVerifyTakeOfferFeePaymentResult called: state = " + state);
-        checkState(state == State.VerifyTakeOfferFeePayment);
-        Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
-        state = State.CreateDepositTx;
-        CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, tradeId, offererInputAmount,
-                tradePubKeyAsHex, arbitratorPubKey);
-    }
-     */
 
     ///////////////////////////////////////////////////////////////////////////////////////////
     // Triggered UI event
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     // Triggered from UI event: Button click "Bank transfer inited"
-    // 9. SendSignedPayoutTx
-    public void handleUIEventBankTransferInited() {
-        log.debug("onUIEventBankTransferInited called: state = " + state);
-        log.debug("state " + state);
+    // 23. SignPayoutTx
+    public void handleUIEventBankTransferStarted() {
+        log.debug("handleUIEventBankTransferStarted called: state = " + state);
 
-        // validation
-        checkState(state.ordinal() >= State.SignAndPublishDepositTx.ordinal() &&
-                state.ordinal() <= State.SetupListenerForBlockChainConfirmation.ordinal());
-
-        state = State.handleUIEventBankTransferInited;
-
-        // next task
         String depositTransactionId = trade.getDepositTx().getHashAsString();
-        Coin tradeAmount = trade.getTradeAmount();
         Coin securityDeposit = trade.getSecurityDeposit();
-        state = State.SendSignedPayoutTx;
-        SendSignedPayoutTx.run(this::handleFault,
-                peer,
-                tradeMessageService,
+        Coin tradeAmount = trade.getTradeAmount();
+        state = State.SignPayoutTx;
+        SignPayoutTx.run(this::handleSignPayoutTxResult,
+                this::handleFault,
                 walletService,
                 tradeId,
                 peersPayoutAddress,
@@ -405,24 +391,55 @@ public class BuyerAcceptsOfferProtocol {
                 tradeAmount);
     }
 
+    // 24a. SendBankTransferInitedMessage
+    private void handleSignPayoutTxResult(String depositTxAsHex,
+                                          String offererSignatureR,
+                                          String offererSignatureS,
+                                          Coin offererPaybackAmount,
+                                          Coin takerPaybackAmount,
+                                          String offererPayoutAddress) {
+        log.debug("handleSignPayoutTxResult called: state = " + state);
+        state = State.SendSignedPayoutTx;
+        SendBankTransferInitedMessage.run(this::handleFault,
+                peer,
+                tradeMessageService,
+                tradeId,
+                depositTxAsHex,
+                offererSignatureR,
+                offererSignatureS,
+                offererPaybackAmount,
+                takerPaybackAmount,
+                offererPayoutAddress);
+
+        verifyTakeOfferFeePayment();
+    }
+
+    // 24b VerifyTakeOfferFeePayment
+    private void verifyTakeOfferFeePayment() {
+        VerifyTakeOfferFeePayment.run(this::handleFault, walletService, this.takeOfferFeeTxId);
+    }
+
 
     ///////////////////////////////////////////////////////////////////////////////////////////
     // Incoming message from peer
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    // 10. handlePayoutTxPublishedMessage
+    // 28. handlePayoutTxPublishedMessage
     public void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage message) {
         log.debug("onPayoutTxPublishedMessage called: state = " + state);
 
-        // validation
-        checkState(state == State.SendSignedPayoutTx);
-        checkTradeId(tradeId, message);
-        String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex());
+        try {
+            // validation
+            checkState(state == State.SendSignedPayoutTx);
+            checkTradeId(tradeId, message);
+            String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex());
 
-        // apply new state
-        state = State.handlePayoutTxPublishedMessage;
-        Transaction payoutTx = new Transaction(walletService.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
-        listener.onPayoutTxPublished(payoutTx);
+            // apply new state
+            Transaction payoutTx = new Transaction(walletService.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
+            listener.onPayoutTxPublished(payoutTx);
+        } catch (Throwable t) {
+            handleValidationFault(t);
+        }
     }
 
 
@@ -430,7 +447,6 @@ public class BuyerAcceptsOfferProtocol {
     // Private
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    // generic fault handler
     private void handleFault(Throwable throwable) {
         trade.setFault(throwable);
         trade.setState(Trade.State.FAILED);
@@ -441,4 +457,9 @@ public class BuyerAcceptsOfferProtocol {
         handleFault(new Exception(errorMessage));
     }
 
+    private void handleValidationFault(Throwable throwable) {
+        throwable.printStackTrace();
+        log.error(throwable.getMessage());
+        handleErrorMessage("Validation of incoming message failed. Error message = " + throwable.getMessage());
+    }
 }
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/CreateDepositTx.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/CreateDepositTx.java
index 163b6a9219..8215e9108d 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/CreateDepositTx.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/CreateDepositTx.java
@@ -17,7 +17,9 @@
 
 package io.bitsquare.trade.protocol.trade.offerer.tasks;
 
+import io.bitsquare.btc.FeePolicy;
 import io.bitsquare.btc.WalletService;
+import io.bitsquare.trade.Trade;
 import io.bitsquare.util.handlers.ExceptionHandler;
 
 import org.bitcoinj.core.Coin;
@@ -34,15 +36,15 @@ public class CreateDepositTx {
     public static void run(ResultHandler resultHandler,
                            ExceptionHandler exceptionHandler,
                            WalletService walletService,
-                           String tradeId,
-                           Coin offererInputAmount,
+                           Trade trade,
                            String takerMultiSigPubKey,
                            String arbitratorPubKeyAsHex) {
         log.trace("Run CreateDepositTx task");
         try {
-            String offererPubKey = walletService.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
+            String offererPubKey = walletService.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
+            Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
             Transaction transaction = walletService.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerMultiSigPubKey,
-                    arbitratorPubKeyAsHex, tradeId);
+                    arbitratorPubKeyAsHex, trade.getId());
 
             String preparedOffererDepositTxAsHex = Utils.HEX.encode(transaction.bitcoinSerialize());
             long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex();
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/SendBankTransferInitedMessage.java
similarity index 59%
rename from gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendSignedPayoutTx.java
rename to gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SendBankTransferInitedMessage.java
index 240a543b94..9151003283 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/SendBankTransferInitedMessage.java
@@ -17,7 +17,6 @@
 
 package io.bitsquare.trade.protocol.trade.offerer.tasks;
 
-import io.bitsquare.btc.WalletService;
 import io.bitsquare.network.Peer;
 import io.bitsquare.trade.TradeMessageService;
 import io.bitsquare.trade.listeners.SendMessageListener;
@@ -25,39 +24,25 @@ import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMess
 import io.bitsquare.util.handlers.ExceptionHandler;
 
 import org.bitcoinj.core.Coin;
-import org.bitcoinj.core.ECKey;
-
-import javafx.util.Pair;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class SendSignedPayoutTx {
-    private static final Logger log = LoggerFactory.getLogger(SendSignedPayoutTx.class);
+public class SendBankTransferInitedMessage {
+    private static final Logger log = LoggerFactory.getLogger(SendBankTransferInitedMessage.class);
 
     public static void run(ExceptionHandler exceptionHandler,
                            Peer peer,
                            TradeMessageService tradeMessageService,
-                           WalletService walletService,
                            String tradeId,
-                           String takerPayoutAddress,
-                           String offererPayoutAddress,
-                           String depositTransactionId,
-                           Coin securityDeposit,
-                           Coin tradeAmount) {
-        log.trace("Run task");
+                           String depositTxAsHex,
+                           String offererSignatureR,
+                           String offererSignatureS,
+                           Coin offererPaybackAmount,
+                           Coin takerPaybackAmount,
+                           String offererPayoutAddress) {
+        log.trace("Run SendSignedPayoutTx task");
         try {
-            Coin offererPaybackAmount = tradeAmount.add(securityDeposit);
-            @SuppressWarnings("UnnecessaryLocalVariable") Coin takerPaybackAmount = securityDeposit;
-
-            Pair<ECKey.ECDSASignature, String> result = walletService.offererCreatesAndSignsPayoutTx(
-                    depositTransactionId, offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, tradeId);
-
-            ECKey.ECDSASignature offererSignature = result.getKey();
-            String offererSignatureR = offererSignature.r.toString();
-            String offererSignatureS = offererSignature.s.toString();
-            String depositTxAsHex = result.getValue();
-
             BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(tradeId,
                     depositTxAsHex,
                     offererSignatureR,
@@ -65,22 +50,19 @@ public class SendSignedPayoutTx {
                     offererPaybackAmount,
                     takerPaybackAmount,
                     offererPayoutAddress);
-
             tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
                 @Override
                 public void handleResult() {
-                    log.trace("BankTransferInitedMessage successfully arrived at peer");
+                    log.trace("Sending BankTransferInitedMessage succeeded.");
                 }
 
                 @Override
                 public void handleFault() {
-                    log.error("BankTransferInitedMessage did not arrive at peer");
-                    exceptionHandler.handleException(new Exception("BankTransferInitedMessage did not arrive at peer"));
+                    exceptionHandler.handleException(new Exception("Sending BankTransferInitedMessage failed."));
 
                 }
             });
         } catch (Exception e) {
-            log.error("Exception at OffererCreatesAndSignsPayoutTx " + e);
             exceptionHandler.handleException(e);
         }
     }
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 557731e8b0..ce5f402065 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
@@ -22,7 +22,6 @@ import io.bitsquare.trade.TradeMessageService;
 import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
 import io.bitsquare.util.handlers.ErrorMessageHandler;
-import io.bitsquare.util.handlers.ResultHandler;
 
 import org.bitcoinj.core.Transaction;
 import org.bitcoinj.core.Utils;
@@ -33,7 +32,7 @@ import org.slf4j.LoggerFactory;
 public class SendDepositTxIdToTaker {
     private static final Logger log = LoggerFactory.getLogger(SendDepositTxIdToTaker.class);
 
-    public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler, Peer peer,
+    public static void run( ErrorMessageHandler errorMessageHandler, Peer peer,
                            TradeMessageService tradeMessageService, String tradeId, Transaction depositTransaction) {
         log.trace("Run task");
         DepositTxPublishedMessage tradeMessage =
@@ -43,7 +42,6 @@ public class SendDepositTxIdToTaker {
             @Override
             public void handleResult() {
                 log.trace("DepositTxPublishedMessage successfully arrived at peer");
-                resultHandler.handleResult();
             }
 
             @Override
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SetupListenerForBlockChainConfirmation.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SetupListenerForBlockChainConfirmation.java
index 64f85b7d9c..0d8bb00fc2 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SetupListenerForBlockChainConfirmation.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SetupListenerForBlockChainConfirmation.java
@@ -25,6 +25,7 @@ import org.bitcoinj.core.TransactionConfidence;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+// TODO should be removed
 public class SetupListenerForBlockChainConfirmation {
     private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
 
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SignPayoutTx.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SignPayoutTx.java
new file mode 100644
index 0000000000..f30058b32f
--- /dev/null
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/SignPayoutTx.java
@@ -0,0 +1,72 @@
+/*
+ * 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.btc.WalletService;
+import io.bitsquare.util.handlers.ExceptionHandler;
+
+import org.bitcoinj.core.Coin;
+import org.bitcoinj.core.ECKey;
+
+import javafx.util.Pair;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SignPayoutTx {
+    private static final Logger log = LoggerFactory.getLogger(SignPayoutTx.class);
+
+    public static void run(ResultHandler resultHandler,
+                           ExceptionHandler exceptionHandler,
+                           WalletService walletService,
+                           String tradeId,
+                           String takerPayoutAddress,
+                           String offererPayoutAddress,
+                           String depositTransactionId,
+                           Coin securityDeposit,
+                           Coin tradeAmount) {
+        log.trace("Run SignPayoutTx task");
+        try {
+            Coin offererPaybackAmount = tradeAmount.add(securityDeposit);
+            @SuppressWarnings("UnnecessaryLocalVariable") Coin takerPaybackAmount = securityDeposit;
+
+            Pair<ECKey.ECDSASignature, String> result = walletService.offererCreatesAndSignsPayoutTx(
+                    depositTransactionId, offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, tradeId);
+
+            ECKey.ECDSASignature offererSignature = result.getKey();
+            String offererSignatureR = offererSignature.r.toString();
+            String offererSignatureS = offererSignature.s.toString();
+            String depositTxAsHex = result.getValue();
+
+            resultHandler.handleResult(depositTxAsHex, offererSignatureR, offererSignatureS, offererPaybackAmount, takerPaybackAmount, offererPayoutAddress);
+        } catch (Exception e) {
+            exceptionHandler.handleException(e);
+        }
+    }
+
+    public interface ResultHandler {
+        void handleResult(String depositTxAsHex,
+                          String offererSignatureR,
+                          String offererSignatureS,
+                          Coin offererPaybackAmount,
+                          Coin takerPaybackAmount,
+                          String offererPayoutAddress);
+    }
+
+}
+
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/VerifyTakeOfferFeePayment.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/VerifyTakeOfferFeePayment.java
index b450d82015..edbc85514d 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/VerifyTakeOfferFeePayment.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/offerer/tasks/VerifyTakeOfferFeePayment.java
@@ -19,7 +19,6 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
 
 import io.bitsquare.btc.WalletService;
 import io.bitsquare.util.handlers.ExceptionHandler;
-import io.bitsquare.util.handlers.ResultHandler;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -27,14 +26,14 @@ import org.slf4j.LoggerFactory;
 public class VerifyTakeOfferFeePayment {
     private static final Logger log = LoggerFactory.getLogger(VerifyTakeOfferFeePayment.class);
 
-    public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, WalletService walletService,
+    public static void run(ExceptionHandler exceptionHandler, WalletService walletService,
                            String takeOfferFeeTxId) {
         log.trace("Run VerifyTakeOfferFeePayment task");
         //TODO mocked yet, need a confidence listeners
         int numOfPeersSeenTx = walletService.getNumOfPeersSeenTx(takeOfferFeeTxId);
-        if (numOfPeersSeenTx > 2) {
+       /* if (numOfPeersSeenTx > 2) {
             resultHandler.handleResult();
-        }
+        }*/
     }
 
 }
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 bdaac46be8..ef07a55d99 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
@@ -41,6 +41,7 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTxAsH
 import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedMessage;
 import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx;
 import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
+import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
 import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount;
 import io.bitsquare.user.User;
 
@@ -73,17 +74,17 @@ public class SellerTakesOfferProtocol {
         GetPeerAddress,
         RequestTakeOffer,
 
-        handleRespondToTakeOfferRequestMessage,
+        ValidateRespondToTakeOfferRequestMessage,
         PayTakeOfferFee,
         SendTakeOfferFeePayedMessage,
 
-        handleTakerDepositPaymentRequestMessage,
+        ValidateTakerDepositPaymentRequestMessage,
         VerifyOffererAccount,
         CreateAndSignContract,
         PayDeposit,
         SendSignedTakerDepositTxAsHex,
 
-        handleDepositTxPublishedMessage,
+        ValidateDepositTxPublishedMessage,
         TakerCommitDepositTx,
         handleBankTransferInitedMessage,
         SignAndPublishPayoutTx,
@@ -197,23 +198,27 @@ public class SellerTakesOfferProtocol {
     public void handleRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message) {
         log.debug("handleRespondToTakeOfferRequestMessage called: state = " + state);
 
-        // validation
-        checkState(state == State.RequestTakeOffer);
-        checkTradeId(tradeId, message);
+        try {
+            // validation
+            checkState(state == State.RequestTakeOffer);
+            state = State.ValidateRespondToTakeOfferRequestMessage;
+            checkTradeId(tradeId, message);
 
-        // apply new state
-        state = State.handleRespondToTakeOfferRequestMessage;
-        if (message.isTakeOfferRequestAccepted()) {
-            trade.setState(Trade.State.OFFERER_ACCEPTED);
-            listener.onTakeOfferRequestAccepted();
+            // apply new state
+            if (message.isTakeOfferRequestAccepted()) {
+                trade.setState(Trade.State.OFFERER_ACCEPTED);
+                listener.onTakeOfferRequestAccepted();
 
-            // next task
-            payTakeOfferFee();
-        }
-        else {
-            // exit case
-            trade.setState(Trade.State.OFFERER_REJECTED);
-            listener.onTakeOfferRequestRejected();
+                // next task
+                payTakeOfferFee();
+            }
+            else {
+                // exit case
+                trade.setState(Trade.State.OFFERER_REJECTED);
+                listener.onTakeOfferRequestRejected();
+            }
+        } catch (Throwable t) {
+            handleValidationFault(t);
         }
     }
 
@@ -228,8 +233,7 @@ public class SellerTakesOfferProtocol {
         log.debug("handlePayTakeOfferFeeResult called: state = " + state);
         trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
         state = State.SendTakeOfferFeePayedMessage;
-        SendTakeOfferFeePayedMessage.run(this::handleErrorMessage, peer,
-                tradeMessageService, tradeId, takeOfferFeeTxId, tradeAmount, tradePubKeyAsHex);
+        SendTakeOfferFeePayedMessage.run(this::handleErrorMessage, peer, tradeMessageService, tradeId, takeOfferFeeTxId, tradeAmount, tradePubKeyAsHex);
     }
 
 
@@ -237,36 +241,44 @@ public class SellerTakesOfferProtocol {
     // Incoming message from peer
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    // 5. VerifyOffererAccount
+    // 11. VerifyOffererAccount
     public void handleTakerDepositPaymentRequestMessage(TakerDepositPaymentRequestMessage message) {
         log.debug("handleTakerDepositPaymentRequestMessage called: state = " + state);
 
-        // validation
-        checkState(state == State.SendTakeOfferFeePayedMessage);
-        checkTradeId(tradeId, message);
-        String peersAccountId = nonEmptyStringOf(message.getAccountId());
-        BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
-        String offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
-        String preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
-        long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
+        try {
+            // validation
+            checkState(state == State.SendTakeOfferFeePayedMessage);
+            state = State.ValidateTakerDepositPaymentRequestMessage;
+            checkTradeId(tradeId, message);
+            String peersAccountId = nonEmptyStringOf(message.getAccountId());
+            BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
+            String offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
+            String preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
+            long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
 
-        // apply new state
-        state = State.handleTakerDepositPaymentRequestMessage;
-        this.peersAccountId = peersAccountId;
-        this.peersBankAccount = peersBankAccount;
-        this.peersPubKey = offererPubKey;
-        this.preparedPeersDepositTxAsHex = preparedOffererDepositTxAsHex;
-        this.peersTxOutIndex = offererTxOutIndex;
+            // apply new state
+            this.peersAccountId = peersAccountId;
+            this.peersBankAccount = peersBankAccount;
+            this.peersPubKey = offererPubKey;
+            this.preparedPeersDepositTxAsHex = preparedOffererDepositTxAsHex;
+            this.peersTxOutIndex = offererTxOutIndex;
 
-        // next task
+            // next task
+            verifyOffererAccount();
+        } catch (Throwable t) {
+            handleValidationFault(t);
+        }
+    }
+
+    // 12. VerifyOffererAccount
+    private void verifyOffererAccount() {
         state = State.VerifyOffererAccount;
         VerifyOffererAccount.run(this::handleVerifyOffererAccountResult, this::handleFault, blockChainService, peersAccountId, peersBankAccount);
     }
 
-    // 6. CreateAndSignContract
+    // 13. CreateAndSignContract
     private void handleVerifyOffererAccountResult() {
         log.debug("handleVerifyOffererAccountResult called: state = " + state);
-        checkState(state == State.VerifyOffererAccount);
         String takeOfferFeeTxId = trade.getTakeOfferFeeTxId();
         state = State.CreateAndSignContract;
         CreateAndSignContract.run(this::handleCreateAndSignContractResult,
@@ -284,10 +296,9 @@ public class SellerTakesOfferProtocol {
                 accountKey);
     }
 
-    // 7. PayDeposit
+    // 14. PayDeposit
     private void handleCreateAndSignContractResult(Contract contract, String contractAsJson, String signature) {
         log.debug("handleCreateAndSignContractResult called: state = " + state);
-        checkState(state == State.CreateAndSignContract);
         trade.setContract(contract);
         trade.setContractAsJson(contractAsJson);
         trade.setTakerContractSignature(signature);
@@ -296,10 +307,9 @@ public class SellerTakesOfferProtocol {
                 tradePubKeyAsHex, arbitratorPubKey, peersPubKey, preparedPeersDepositTxAsHex);
     }
 
-    // 8. SendSignedTakerDepositTxAsHex
+    // 15. SendSignedTakerDepositTxAsHex
     private void handlePayDepositResult(Transaction signedTakerDepositTx) {
         log.debug("handlePayDepositResult called: state = " + state);
-        checkState(state == State.PayDeposit);
         String contractAsJson = trade.getContractAsJson();
         String takerContractSignature = trade.getTakerContractSignature();
         state = State.SendSignedTakerDepositTxAsHex;
@@ -322,29 +332,37 @@ public class SellerTakesOfferProtocol {
     // Incoming message from peer
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    // 9.a TakerCommitDepositTx
+    // 21. TakerCommitDepositTx
     public void handleDepositTxPublishedMessage(DepositTxPublishedMessage message) {
         log.debug("onDepositTxPublishedMessage called: state = " + state);
         log.debug("state " + state);
 
+        try {
+            // validation
+            checkState(state == State.SendSignedTakerDepositTxAsHex);
+            state = State.ValidateDepositTxPublishedMessage;
+            checkTradeId(tradeId, message);
+            String depositTxAsHex = message.getDepositTxAsHex();
+            nonEmptyStringOf(depositTxAsHex);
 
-        // validation
-        checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal());
-        checkTradeId(tradeId, message);
-        nonEmptyStringOf(message.getDepositTxAsHex());
+            // next task
+            takerCommitDepositTx(depositTxAsHex);
+        } catch (Throwable t) {
+            handleValidationFault(t);
+        }
+    }
 
-        // apply new state
-        state = State.handleDepositTxPublishedMessage;
-        String depositTxAsHex = message.getDepositTxAsHex();
-
-        // next task
+    // 22. TakerCommitDepositTx
+    private void takerCommitDepositTx(String depositTxAsHex) {
         state = State.TakerCommitDepositTx;
         TakerCommitDepositTx.run(this::handleTakerCommitDepositTxResult, this::handleFault, walletService, depositTxAsHex);
     }
 
     private void handleTakerCommitDepositTxResult(Transaction transaction) {
         log.debug("handleTakerCommitDepositTxResult called: state = " + state);
-        listener.onDepositTxPublished(transaction);
+        trade.setDepositTx(transaction);
+        trade.setState(Trade.State.DEPOSIT_PUBLISHED);
+        listener.onDepositTxPublished();
     }
 
 
@@ -352,32 +370,34 @@ public class SellerTakesOfferProtocol {
     // Incoming message from peer
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    // 9.b. handleBankTransferInitedMessage
+    // 25. handleBankTransferInitedMessage
     public void handleBankTransferInitedMessage(BankTransferInitedMessage message) {
-        log.debug("onBankTransferInitedMessage called: state = " + state);
-        log.debug("state " + state);
+        log.debug("handleBankTransferInitedMessage called: state = " + state);
 
-        // validate
-        checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal() &&
-                state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
-        checkTradeId(tradeId, message);
-        String depositTxAsHex = nonEmptyStringOf(message.getDepositTxAsHex());
-        String offererSignatureR = nonEmptyStringOf(message.getOffererSignatureR());
-        String offererSignatureS = nonEmptyStringOf(message.getOffererSignatureS());
-        Coin offererPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getOffererPaybackAmount()));
-        Coin takerPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getTakerPaybackAmount()));
-        String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress());
+        try {
+            // validate
+            checkState(state == State.TakerCommitDepositTx);
+            checkTradeId(tradeId, message);
+            String depositTxAsHex = nonEmptyStringOf(message.getDepositTxAsHex());
+            String offererSignatureR = nonEmptyStringOf(message.getOffererSignatureR());
+            String offererSignatureS = nonEmptyStringOf(message.getOffererSignatureS());
+            Coin offererPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getOffererPaybackAmount()));
+            Coin takerPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getTakerPaybackAmount()));
+            String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress());
 
-        // apply state
-        state = State.handleBankTransferInitedMessage;
-        this.depositTxAsHex = depositTxAsHex;
-        this.offererSignatureR = offererSignatureR;
-        this.offererSignatureS = offererSignatureS;
-        this.offererPaybackAmount = offererPaybackAmount;
-        this.takerPaybackAmount = takerPaybackAmount;
-        this.offererPayoutAddress = offererPayoutAddress;
+            // apply state
+            state = State.handleBankTransferInitedMessage;
+            this.depositTxAsHex = depositTxAsHex;
+            this.offererSignatureR = offererSignatureR;
+            this.offererSignatureS = offererSignatureS;
+            this.offererPaybackAmount = offererPaybackAmount;
+            this.takerPaybackAmount = takerPaybackAmount;
+            this.offererPayoutAddress = offererPayoutAddress;
 
-        listener.onBankTransferInited(message.getTradeId());
+            listener.onBankTransferInited(message.getTradeId());
+        } catch (Throwable t) {
+            handleValidationFault(t);
+        }
     }
 
 
@@ -386,11 +406,10 @@ public class SellerTakesOfferProtocol {
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     // User clicked the "bank transfer received" button, so we release the funds for pay out
-    // 10. SignAndPublishPayoutTx
+    // 26. SignAndPublishPayoutTx
     public void handleUIEventFiatReceived() {
-        log.debug("onUIEventFiatReceived called: state = " + state);
-        log.debug("state " + state);
-        checkState(state == State.handleBankTransferInitedMessage || state == State.TakerCommitDepositTx);
+        log.debug("handleUIEventFiatReceived called: state = " + state);
+        checkState(state == State.handleBankTransferInitedMessage);
 
         state = State.SignAndPublishPayoutTx;
         SignAndPublishPayoutTx.run(this::handleSignAndPublishPayoutTxResult,
@@ -403,19 +422,21 @@ public class SellerTakesOfferProtocol {
                 offererPaybackAmount,
                 takerPaybackAmount,
                 offererPayoutAddress);
+
+        verifyOfferFeePayment();
     }
 
-    // 11. SendPayoutTxToOfferer
+    // 27a. SendPayoutTxToOfferer
     private void handleSignAndPublishPayoutTxResult(Transaction transaction, String payoutTxAsHex) {
         log.debug("handleSignAndPublishPayoutTxResult called: state = " + state);
         listener.onPayoutTxPublished(trade, transaction);
         state = State.SendPayoutTxToOfferer;
-        SendPayoutTxToOfferer.run(this::handleSendPayoutTxToOffererResult, this::handleErrorMessage, peer, tradeMessageService,
-                tradeId, payoutTxAsHex);
+        SendPayoutTxToOfferer.run(this::handleErrorMessage, peer, tradeMessageService, tradeId, payoutTxAsHex);
     }
 
-    private void handleSendPayoutTxToOffererResult() {
-        log.debug("onResultSendPayoutTxToOfferer called: state = " + state);
+    // 27b VerifyTakeOfferFeePayment
+    private void verifyOfferFeePayment() {
+        VerifyOfferFeePayment.run(this::handleFault, walletService, trade.getOffer().getOfferFeePaymentTxID());
     }
 
 
@@ -423,7 +444,6 @@ public class SellerTakesOfferProtocol {
     // Private
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    // generic fault handler
     private void handleFault(Throwable throwable) {
         trade.setFault(throwable);
         trade.setState(Trade.State.FAILED);
@@ -434,4 +454,9 @@ public class SellerTakesOfferProtocol {
         handleFault(new Exception(errorMessage));
     }
 
+    private void handleValidationFault(Throwable throwable) {
+        throwable.printStackTrace();
+        log.error(throwable.getMessage());
+        handleErrorMessage("Validation of incoming message failed. Error message = " + throwable.getMessage());
+    }
 }
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 5fae11fb75..fe0a7d7ee8 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
@@ -22,7 +22,6 @@ import io.bitsquare.trade.TradeMessageService;
 import io.bitsquare.trade.listeners.SendMessageListener;
 import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
 import io.bitsquare.util.handlers.ErrorMessageHandler;
-import io.bitsquare.util.handlers.ResultHandler;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,21 +29,18 @@ import org.slf4j.LoggerFactory;
 public class SendPayoutTxToOfferer {
     private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class);
 
-    public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler, Peer peer,
-                           TradeMessageService tradeMessageService, String tradeId, String payoutTxAsHex) {
-        log.trace("Run task");
+    public static void run(ErrorMessageHandler errorMessageHandler, Peer peer, TradeMessageService tradeMessageService, String tradeId, String payoutTxAsHex) {
+        log.trace("Run SendPayoutTxToOfferer task");
         PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex);
         tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
             @Override
             public void handleResult() {
                 log.trace("PayoutTxPublishedMessage successfully arrived at peer");
-                resultHandler.handleResult();
             }
 
             @Override
             public void handleFault() {
-                log.error("PayoutTxPublishedMessage  did not arrive at peer");
-                errorMessageHandler.handleErrorMessage("PayoutTxPublishedMessage did not arrive at peer");
+                errorMessageHandler.handleErrorMessage("Sending PayoutTxPublishedMessage failed.");
             }
         });
 
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SignAndPublishPayoutTx.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SignAndPublishPayoutTx.java
index 15be8475e5..742fc2fffd 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SignAndPublishPayoutTx.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/SignAndPublishPayoutTx.java
@@ -44,9 +44,8 @@ public class SignAndPublishPayoutTx {
                            Coin offererPaybackAmount,
                            Coin takerPaybackAmount,
                            String offererPayoutAddress) {
-        log.trace("Run task");
+        log.trace("Run SignAndPublishPayoutTx task");
         try {
-
             walletService.takerSignsAndSendsTx(depositTxAsHex,
                     offererSignatureR,
                     offererSignatureS,
@@ -64,12 +63,10 @@ public class SignAndPublishPayoutTx {
 
                         @Override
                         public void onFailure(@NotNull Throwable t) {
-                            log.error("Exception at takerSignsAndSendsTx " + t);
                             exceptionHandler.handleException(t);
                         }
                     });
         } catch (Exception e) {
-            log.error("Exception at takerSignsAndSendsTx " + e);
             exceptionHandler.handleException(e);
         }
     }
diff --git a/gui/src/main/java/io/bitsquare/trade/TradeMessage.java b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/VerifyOfferFeePayment.java
similarity index 52%
rename from gui/src/main/java/io/bitsquare/trade/TradeMessage.java
rename to gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/VerifyOfferFeePayment.java
index beb1cde648..0c809f18e2 100644
--- a/gui/src/main/java/io/bitsquare/trade/TradeMessage.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/trade/taker/tasks/VerifyOfferFeePayment.java
@@ -15,17 +15,25 @@
  * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package io.bitsquare.trade;
+package io.bitsquare.trade.protocol.trade.taker.tasks;
 
-import io.bitsquare.network.Message;
+import io.bitsquare.btc.WalletService;
+import io.bitsquare.util.handlers.ExceptionHandler;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class TradeMessage implements Message {
-    private static final Logger log = LoggerFactory.getLogger(TradeMessage.class);
-
-    public TradeMessage() {
+public class VerifyOfferFeePayment {
+    private static final Logger log = LoggerFactory.getLogger(VerifyOfferFeePayment.class);
 
+    public static void run(ExceptionHandler exceptionHandler, WalletService walletService,
+                           String takeOfferFeeTxId) {
+        log.trace("Run VerifyOfferFeePayment task");
+        //TODO mocked yet, need a confidence listeners
+        int numOfPeersSeenTx = walletService.getNumOfPeersSeenTx(takeOfferFeeTxId);
+       /* if (numOfPeersSeenTx > 2) {
+            resultHandler.handleResult();
+        }*/
     }
+
 }