From 9c8ae1bc101ed1a0d1c8a2f8bf1b11fa29372e18 Mon Sep 17 00:00:00 2001
From: Manfred Karrer <mk@nucleo.io>
Date: Mon, 9 Mar 2015 14:26:17 +0100
Subject: [PATCH] Add OpenOffer

---
 .../main/portfolio/offer/OffersDataModel.java | 22 +++--
 .../gui/main/portfolio/offer/OffersView.java  | 94 +++++++++----------
 .../main/portfolio/offer/OffersViewModel.java | 30 +++---
 ...erListItem.java => OpenOfferListItem.java} | 14 +--
 .../trade/offerbook/OfferBookDataModel.java   |  4 +-
 .../main/trade/offerbook/OfferBookView.java   |  4 +-
 .../trade/offerbook/OfferBookViewModel.java   |  4 +-
 .../main/java/io/bitsquare/offer/Offer.java   |  8 +-
 .../java/io/bitsquare/offer/OfferBook.java    |  2 +-
 .../java/io/bitsquare/offer/OpenOffer.java    | 43 +++++++++
 .../java/io/bitsquare/trade/TradeManager.java | 43 ++++-----
 .../placeoffer/PlaceOfferProtocol.java        |  2 +-
 12 files changed, 160 insertions(+), 110 deletions(-)
 rename gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/{OfferListItem.java => OpenOfferListItem.java} (77%)
 create mode 100644 gui/src/main/java/io/bitsquare/offer/OpenOffer.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 66c9cab0b5..79586ce9d9 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
@@ -19,6 +19,7 @@ package io.bitsquare.gui.main.portfolio.offer;
 
 import io.bitsquare.offer.Direction;
 import io.bitsquare.offer.Offer;
+import io.bitsquare.offer.OpenOffer;
 import io.bitsquare.trade.TradeManager;
 import io.bitsquare.user.User;
 import io.bitsquare.util.handlers.ErrorMessageHandler;
@@ -44,8 +45,8 @@ class OffersDataModel implements Activatable, DataModel {
     private final TradeManager tradeManager;
     private final User user;
 
-    private final ObservableList<OfferListItem> list = FXCollections.observableArrayList();
-    private final MapChangeListener<String, Offer> offerMapChangeListener;
+    private final ObservableList<OpenOfferListItem> list = FXCollections.observableArrayList();
+    private final MapChangeListener<String, OpenOffer> offerMapChangeListener;
 
 
     @Inject
@@ -55,19 +56,19 @@ class OffersDataModel implements Activatable, DataModel {
 
         this.offerMapChangeListener = change -> {
             if (change.wasAdded())
-                list.add(new OfferListItem(change.getValueAdded()));
+                list.add(new OpenOfferListItem(change.getValueAdded()));
             else if (change.wasRemoved())
-                list.removeIf(e -> e.getOffer().getId().equals(change.getValueRemoved().getId()));
+                list.removeIf(e -> e.getOpenOffer().getId().equals(change.getValueRemoved().getId()));
         };
     }
 
     @Override
     public void activate() {
         list.clear();
-        list.addAll(tradeManager.getOpenOffers().values().stream().map(OfferListItem::new).collect(Collectors.toList()));
+        list.addAll(tradeManager.getOpenOffers().values().stream().map(OpenOfferListItem::new).collect(Collectors.toList()));
 
         // we sort by date, earliest first
-        list.sort((o1, o2) -> o2.getOffer().getCreationDate().compareTo(o1.getOffer().getCreationDate()));
+        list.sort((o1, o2) -> o2.getOpenOffer().getOffer().getCreationDate().compareTo(o1.getOpenOffer().getOffer().getCreationDate()));
 
         tradeManager.getOpenOffers().addListener(offerMapChangeListener);
     }
@@ -77,16 +78,17 @@ class OffersDataModel implements Activatable, DataModel {
         tradeManager.getOpenOffers().removeListener(offerMapChangeListener);
     }
 
-    void removeOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
-        tradeManager.requestRemoveOffer(offer, resultHandler, errorMessageHandler);
+    void removeOpenOffer(String offerId, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
+        tradeManager.requestRemoveOpenOffer(offerId, resultHandler, errorMessageHandler);
     }
 
 
-    public ObservableList<OfferListItem> getList() {
+    public ObservableList<OpenOfferListItem> getList() {
         return list;
     }
 
-    public Direction getDirection(Offer offer) {
+    public Direction getDirection(OpenOffer openOffer) {
+        Offer offer = openOffer.getOffer();
         return offer.getMessagePublicKey().equals(user.getMessagePublicKey()) ?
                 offer.getDirection() : offer.getMirroredDirection();
     }
diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java
index 947665cc0e..99ed4418cd 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java
@@ -35,8 +35,8 @@ import javafx.util.Callback;
 @FxmlView
 public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewModel> {
 
-    @FXML TableView<OfferListItem> table;
-    @FXML TableColumn<OfferListItem, OfferListItem> priceColumn, amountColumn, volumeColumn,
+    @FXML TableView<OpenOfferListItem> table;
+    @FXML TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, amountColumn, volumeColumn,
             directionColumn, dateColumn, offerIdColumn, removeItemColumn;
 
     @Inject
@@ -63,14 +63,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
         table.setItems(model.getList());
     }
 
-    private void removeOffer(OfferListItem item) {
-        model.removeOffer(item);
+    private void removeOpenOffer(String offerId) {
+        model.removeOpenOffer(offerId);
     }
 
-    private void openOfferDetails(OfferListItem item) {
+    private void openOfferDetails(OpenOfferListItem item) {
         // TODO Open popup with details view
         log.debug("openOfferDetails " + item);
-        Utilities.copyToClipboard(item.getOffer().getId());
+        Utilities.copyToClipboard(item.getOpenOffer().getId());
         Popups.openWarningPopup("Under construction",
                 "The offer ID was copied to the clipboard. " +
                         "Use that to identify your trading peer in the IRC chat room \n\n" +
@@ -80,16 +80,16 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
     private void setOfferIdColumnCellFactory() {
         offerIdColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
         offerIdColumn.setCellFactory(
-                new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem, OfferListItem>>() {
+                new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() {
 
                     @Override
-                    public TableCell<OfferListItem, OfferListItem> call(TableColumn<OfferListItem,
-                            OfferListItem> column) {
-                        return new TableCell<OfferListItem, OfferListItem>() {
+                    public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem,
+                            OpenOfferListItem> column) {
+                        return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
                             private Hyperlink hyperlink;
 
                             @Override
-                            public void updateItem(final OfferListItem item, boolean empty) {
+                            public void updateItem(final OpenOfferListItem item, boolean empty) {
                                 super.updateItem(item, empty);
 
                                 if (item != null && !empty) {
@@ -112,14 +112,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
     private void setDateColumnCellFactory() {
         dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
         dateColumn.setCellFactory(
-                new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
-                        OfferListItem>>() {
+                new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem,
+                        OpenOfferListItem>>() {
                     @Override
-                    public TableCell<OfferListItem, OfferListItem> call(
-                            TableColumn<OfferListItem, OfferListItem> column) {
-                        return new TableCell<OfferListItem, OfferListItem>() {
+                    public TableCell<OpenOfferListItem, OpenOfferListItem> call(
+                            TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
+                        return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
                             @Override
-                            public void updateItem(final OfferListItem item, boolean empty) {
+                            public void updateItem(final OpenOfferListItem item, boolean empty) {
                                 super.updateItem(item, empty);
                                 if (item != null)
                                     setText(model.getDate(item));
@@ -134,14 +134,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
     private void setAmountColumnCellFactory() {
         amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
         amountColumn.setCellFactory(
-                new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
-                        OfferListItem>>() {
+                new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem,
+                        OpenOfferListItem>>() {
                     @Override
-                    public TableCell<OfferListItem, OfferListItem> call(
-                            TableColumn<OfferListItem, OfferListItem> column) {
-                        return new TableCell<OfferListItem, OfferListItem>() {
+                    public TableCell<OpenOfferListItem, OpenOfferListItem> call(
+                            TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
+                        return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
                             @Override
-                            public void updateItem(final OfferListItem item, boolean empty) {
+                            public void updateItem(final OpenOfferListItem item, boolean empty) {
                                 super.updateItem(item, empty);
                                 setText(model.getAmount(item));
                             }
@@ -153,14 +153,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
     private void setPriceColumnCellFactory() {
         priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
         priceColumn.setCellFactory(
-                new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
-                        OfferListItem>>() {
+                new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem,
+                        OpenOfferListItem>>() {
                     @Override
-                    public TableCell<OfferListItem, OfferListItem> call(
-                            TableColumn<OfferListItem, OfferListItem> column) {
-                        return new TableCell<OfferListItem, OfferListItem>() {
+                    public TableCell<OpenOfferListItem, OpenOfferListItem> call(
+                            TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
+                        return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
                             @Override
-                            public void updateItem(final OfferListItem item, boolean empty) {
+                            public void updateItem(final OpenOfferListItem item, boolean empty) {
                                 super.updateItem(item, empty);
                                 setText(model.getPrice(item));
                             }
@@ -172,14 +172,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
     private void setVolumeColumnCellFactory() {
         volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
         volumeColumn.setCellFactory(
-                new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
-                        OfferListItem>>() {
+                new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem,
+                        OpenOfferListItem>>() {
                     @Override
-                    public TableCell<OfferListItem, OfferListItem> call(
-                            TableColumn<OfferListItem, OfferListItem> column) {
-                        return new TableCell<OfferListItem, OfferListItem>() {
+                    public TableCell<OpenOfferListItem, OpenOfferListItem> call(
+                            TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
+                        return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
                             @Override
-                            public void updateItem(final OfferListItem item, boolean empty) {
+                            public void updateItem(final OpenOfferListItem item, boolean empty) {
                                 super.updateItem(item, empty);
                                 if (item != null)
                                     setText(model.getVolume(item));
@@ -194,14 +194,14 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
     private void setDirectionColumnCellFactory() {
         directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
         directionColumn.setCellFactory(
-                new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem,
-                        OfferListItem>>() {
+                new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem,
+                        OpenOfferListItem>>() {
                     @Override
-                    public TableCell<OfferListItem, OfferListItem> call(
-                            TableColumn<OfferListItem, OfferListItem> column) {
-                        return new TableCell<OfferListItem, OfferListItem>() {
+                    public TableCell<OpenOfferListItem, OpenOfferListItem> call(
+                            TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
+                        return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
                             @Override
-                            public void updateItem(final OfferListItem item, boolean empty) {
+                            public void updateItem(final OpenOfferListItem item, boolean empty) {
                                 super.updateItem(item, empty);
                                 setText(model.getDirectionLabel(item));
                             }
@@ -213,11 +213,11 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
     private void setRemoveColumnCellFactory() {
         removeItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
         removeItemColumn.setCellFactory(
-                new Callback<TableColumn<OfferListItem, OfferListItem>, TableCell<OfferListItem, OfferListItem>>() {
+                new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() {
                     @Override
-                    public TableCell<OfferListItem, OfferListItem> call(TableColumn<OfferListItem,
-                            OfferListItem> directionColumn) {
-                        return new TableCell<OfferListItem, OfferListItem>() {
+                    public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem,
+                            OpenOfferListItem> directionColumn) {
+                        return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
                             final ImageView iconView = new ImageView();
                             final Button button = new Button();
 
@@ -229,11 +229,11 @@ public class OffersView extends ActivatableViewAndModel<GridPane, OffersViewMode
                             }
 
                             @Override
-                            public void updateItem(final OfferListItem item, boolean empty) {
+                            public void updateItem(final OpenOfferListItem item, boolean empty) {
                                 super.updateItem(item, empty);
 
                                 if (item != null) {
-                                    button.setOnAction(event -> removeOffer(item));
+                                    button.setOnAction(event -> removeOpenOffer(item.getOpenOffer().getId()));
                                     setGraphic(button);
                                 }
                                 else {
diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java
index c5308340ce..9a149977d5 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java
@@ -44,8 +44,8 @@ class OffersViewModel extends ActivatableWithDataModel<OffersDataModel> implemen
     }
 
 
-    void removeOffer(OfferListItem item) {
-        dataModel.removeOffer(item.getOffer(),
+    void removeOpenOffer(String offerId) {
+        dataModel.removeOpenOffer(offerId,
                 () -> {
                     // visual feedback?
                     log.debug("Remove offer was successful");
@@ -56,32 +56,32 @@ class OffersViewModel extends ActivatableWithDataModel<OffersDataModel> implemen
                 });
     }
 
-    public ObservableList<OfferListItem> getList() {
+    public ObservableList<OpenOfferListItem> getList() {
         return dataModel.getList();
     }
 
-    String getTradeId(OfferListItem item) {
-        return item.getOffer().getId();
+    String getTradeId(OpenOfferListItem item) {
+        return item.getOpenOffer().getId();
     }
 
-    String getAmount(OfferListItem item) {
-        return (item != null) ? formatter.formatAmountWithMinAmount(item.getOffer()) : "";
+    String getAmount(OpenOfferListItem item) {
+        return (item != null) ? formatter.formatAmountWithMinAmount(item.getOpenOffer().getOffer()) : "";
     }
 
-    String getPrice(OfferListItem item) {
-        return (item != null) ? formatter.formatFiat(item.getOffer().getPrice()) : "";
+    String getPrice(OpenOfferListItem item) {
+        return (item != null) ? formatter.formatFiat(item.getOpenOffer().getOffer().getPrice()) : "";
     }
 
-    String getVolume(OfferListItem item) {
-        return (item != null) ? formatter.formatVolumeWithMinVolume(item.getOffer()) : "";
+    String getVolume(OpenOfferListItem item) {
+        return (item != null) ? formatter.formatVolumeWithMinVolume(item.getOpenOffer().getOffer()) : "";
     }
 
-    String getDirectionLabel(OfferListItem item) {
-        return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getOffer())) : "";
+    String getDirectionLabel(OpenOfferListItem item) {
+        return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getOpenOffer())) : "";
     }
 
-    String getDate(OfferListItem item) {
-        return formatter.formatDateTime(item.getOffer().getCreationDate());
+    String getDate(OpenOfferListItem item) {
+        return formatter.formatDateTime(item.getOpenOffer().getOffer().getCreationDate());
     }
 
 }
diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OfferListItem.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OpenOfferListItem.java
similarity index 77%
rename from gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OfferListItem.java
rename to gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OpenOfferListItem.java
index 51cec54090..24351687d6 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OfferListItem.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OpenOfferListItem.java
@@ -17,20 +17,20 @@
 
 package io.bitsquare.gui.main.portfolio.offer;
 
-import io.bitsquare.offer.Offer;
+import io.bitsquare.offer.OpenOffer;
 
 /**
  * We could remove that wrapper if it is not needed for additional UI only fields.
  */
-class OfferListItem {
+class OpenOfferListItem {
 
-    private final Offer offer;
+    private final OpenOffer openOffer;
 
-    public OfferListItem(Offer offer) {
-        this.offer = offer;
+    public OpenOfferListItem(OpenOffer openOffer) {
+        this.openOffer = openOffer;
     }
 
-    public Offer getOffer() {
-        return offer;
+    public OpenOffer getOpenOffer() {
+        return openOffer;
     }
 }
diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java
index 1710ca811f..017ed56540 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java
@@ -114,8 +114,8 @@ class OfferBookDataModel implements Activatable, DataModel {
         btcCode.unbind();
     }
 
-    void removeOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
-        tradeManager.requestRemoveOffer(offer, resultHandler, errorMessageHandler);
+    void removeOpenOffer(String offerId, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
+        tradeManager.requestRemoveOpenOffer(offerId, resultHandler, errorMessageHandler);
     }
 
     void calculateVolume() {
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 16f4d5efc7..6d0489a349 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
@@ -468,8 +468,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
                                     if (model.isMyOffer(offer)) {
                                         iconView.setId("image-remove");
                                         title = "Remove";
-                                        button.setOnAction(event -> model.removeOffer(item
-                                                .getOffer()));
+                                        button.setOnAction(event -> model.removeOpenOffer(item
+                                                .getOffer().getId()));
                                     }
                                     else {
                                         if (offer.getDirection() == Direction.SELL)
diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java
index 88e6898844..1319daf2a5 100644
--- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java
+++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java
@@ -103,8 +103,8 @@ class OfferBookViewModel extends ActivatableWithDataModel<OfferBookDataModel> im
                 (newValue)));
     }
 
-    void removeOffer(Offer offer) {
-        dataModel.removeOffer(offer,
+    void removeOpenOffer(String offerId) {
+        dataModel.removeOpenOffer(offerId,
                 () -> {
                     // visual feedback?
                     log.debug("Remove offer was successful");
diff --git a/gui/src/main/java/io/bitsquare/offer/Offer.java b/gui/src/main/java/io/bitsquare/offer/Offer.java
index 9df82065e1..e567dbdb3d 100644
--- a/gui/src/main/java/io/bitsquare/offer/Offer.java
+++ b/gui/src/main/java/io/bitsquare/offer/Offer.java
@@ -76,9 +76,13 @@ public class Offer implements Serializable {
     private final String bankAccountUID;
     private final List<Arbitrator> arbitrators;
 
+    // Mutable property. Has to be set before offer is save in DHT as it changes the objects hash!
     private String offerFeePaymentTxID;
-    private State state = State.UNKNOWN;
-    private transient ObjectProperty<State> stateProperty; // don't access directly, use getStateProperty()
+
+    // Those state properties are transient and only used at runtime! 
+    private transient State state = State.UNKNOWN;
+    // don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated
+    private transient ObjectProperty<State> stateProperty;
 
 
     ///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/gui/src/main/java/io/bitsquare/offer/OfferBook.java b/gui/src/main/java/io/bitsquare/offer/OfferBook.java
index f039f4f6cc..3c26572a53 100644
--- a/gui/src/main/java/io/bitsquare/offer/OfferBook.java
+++ b/gui/src/main/java/io/bitsquare/offer/OfferBook.java
@@ -139,7 +139,7 @@ public class OfferBook {
             country = bankAccount.getCountry();
             fiatCode = bankAccount.getCurrency().getCurrencyCode();
 
-            // TODO check why that was used
+            // TODO check why that was used (probably just for update triggering, if so refactor that)
             //offerBookListItems.stream().forEach(e -> e.setBankAccountCountry(country));
         }
         else {
diff --git a/gui/src/main/java/io/bitsquare/offer/OpenOffer.java b/gui/src/main/java/io/bitsquare/offer/OpenOffer.java
new file mode 100644
index 0000000000..215d03c80b
--- /dev/null
+++ b/gui/src/main/java/io/bitsquare/offer/OpenOffer.java
@@ -0,0 +1,43 @@
+/*
+ * 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.offer;
+
+import java.io.Serializable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OpenOffer implements Serializable  {
+    private static final long serialVersionUID = -7523483764145982933L;
+    
+    private static final Logger log = LoggerFactory.getLogger(OpenOffer.class);
+    
+    private final Offer offer;
+
+    public OpenOffer( Offer offer) {
+        this.offer = offer;
+    }
+
+    public Offer getOffer() {
+        return offer;
+    }
+
+    public String getId() {
+        return offer.getId();
+    }
+}
diff --git a/gui/src/main/java/io/bitsquare/trade/TradeManager.java b/gui/src/main/java/io/bitsquare/trade/TradeManager.java
index a6d831a833..2d211ee10c 100644
--- a/gui/src/main/java/io/bitsquare/trade/TradeManager.java
+++ b/gui/src/main/java/io/bitsquare/trade/TradeManager.java
@@ -27,6 +27,7 @@ import io.bitsquare.network.Peer;
 import io.bitsquare.offer.Direction;
 import io.bitsquare.offer.Offer;
 import io.bitsquare.offer.OfferBookService;
+import io.bitsquare.offer.OpenOffer;
 import io.bitsquare.persistence.Persistence;
 import io.bitsquare.trade.handlers.TransactionResultHandler;
 import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
@@ -94,7 +95,7 @@ public class TradeManager {
     private final Map<String, BuyerAcceptsOfferProtocol> offererAsBuyerProtocolMap = new HashMap<>();
     private final Map<String, RequestIsOfferAvailableProtocol> requestIsOfferAvailableProtocolMap = new HashMap<>();
 
-    private final ObservableMap<String, Offer> openOffers = FXCollections.observableHashMap();
+    private final ObservableMap<String, OpenOffer> openOffers = FXCollections.observableHashMap();
     private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
     private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
 
@@ -121,9 +122,9 @@ public class TradeManager {
         this.signatureService = signatureService;
         this.offerBookService = offerBookService;
 
-        Object offersObject = persistence.read(this, "offers");
-        if (offersObject instanceof Map) {
-            openOffers.putAll((Map<String, Offer>) offersObject);
+        Object openOffersObject = persistence.read(this, "openOffers");
+        if (openOffersObject instanceof Map) {
+            openOffers.putAll((Map<String, OpenOffer>) openOffersObject);
         }
 
         Object pendingTradesObject = persistence.read(this, "pendingTrades");
@@ -177,12 +178,13 @@ public class TradeManager {
                 accountSettings.getAcceptedCountries(),
                 accountSettings.getAcceptedLanguageLocales());
 
+
         PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
                 offer,
                 walletService,
                 offerBookService,
                 (transaction) -> {
-                    saveOffer(offer);
+                    saveOpenOffer(new OpenOffer(offer));
                     resultHandler.handleResult(transaction);
                 },
                 (message, throwable) -> errorMessageHandler.handleErrorMessage(message)
@@ -191,22 +193,22 @@ public class TradeManager {
         placeOfferProtocol.placeOffer();
     }
 
-    private void saveOffer(Offer offer) {
-        openOffers.put(offer.getId(), offer);
-        persistOffers();
+    private void saveOpenOffer(OpenOffer openOffer) {
+        openOffers.put(openOffer.getId(), openOffer);
+        persistOpenOffers();
     }
 
-    public void requestRemoveOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
-        offerBookService.removeOffer(offer,
+    public void requestRemoveOpenOffer(String offerId, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
+        offerBookService.removeOffer(openOffers.get(offerId).getOffer(),
                 () -> {
-                    if (openOffers.containsKey(offer.getId())) {
-                        openOffers.remove(offer.getId());
-                        persistOffers();
+                    if (openOffers.containsKey(offerId)) {
+                        openOffers.remove(offerId);
+                        persistOpenOffers();
                         resultHandler.handleResult();
                     }
                     else {
-                        log.error("Locally stored offers does not contain the offer with the ID " + offer.getId());
-                        errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offer.getId());
+                        log.error("Locally stored offers does not contain the offer with the ID " + offerId);
+                        errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offerId);
                     }
                 },
                 (message, throwable) -> errorMessageHandler.handleErrorMessage(message));
@@ -247,8 +249,7 @@ public class TradeManager {
     private void createOffererAsBuyerProtocol(String offerId, Peer sender) {
         log.trace("createOffererAsBuyerProtocol offerId = " + offerId);
         if (openOffers.containsKey(offerId)) {
-            Offer offer = openOffers.get(offerId);
-
+            Offer offer = openOffers.get(offerId).getOffer();
             Trade trade = createTrade(offer);
             currentPendingTrade = trade;
 
@@ -264,7 +265,7 @@ public class TradeManager {
                         public void onOfferAccepted(Offer offer) {
                             trade.setState(Trade.State.OFFERER_ACCEPTED);
                             persistPendingTrades();
-                            requestRemoveOffer(offer,
+                            requestRemoveOpenOffer(offer.getId(),
                                     () -> log.debug("remove was successful"),
                                     (message) -> log.error(message));
                         }
@@ -535,7 +536,7 @@ public class TradeManager {
     // Getters
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    public ObservableMap<String, Offer> getOpenOffers() {
+    public ObservableMap<String, OpenOffer> getOpenOffers() {
         return openOffers;
     }
 
@@ -563,8 +564,8 @@ public class TradeManager {
     // Private
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    private void persistOffers() {
-        persistence.write(this, "offers", (Map<String, Offer>) new HashMap<>(openOffers));
+    private void persistOpenOffers() {
+        persistence.write(this, "openOffers", (Map<String, OpenOffer>) new HashMap<>(openOffers));
     }
 
     private void persistPendingTrades() {
diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java b/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java
index 270ace95a5..b67a465c29 100644
--- a/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java
+++ b/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java
@@ -128,7 +128,7 @@ public class PlaceOfferProtocol {
     void addOffer(Transaction transaction) {
         // need to write data before storage, otherwise hash is different when removing offer!
         offer.setOfferFeePaymentTxID(transaction.getHashAsString());
-        
+
         offerBookService.addOffer(offer,
                 () -> {
                     resultHandler.handleResult(transaction);