From 16100e2f8b92a4306c2593a2461dfb416fa66a06 Mon Sep 17 00:00:00 2001
From: Manfred Karrer <mk@nucleo.io>
Date: Fri, 13 Mar 2015 23:22:56 +0100
Subject: [PATCH] Handle create offer error cases

---
 .../main/java/io/bitsquare/btc/FeePolicy.java |  2 +-
 .../createoffer/CreateOfferViewModel.java     |  6 +-
 .../trade/takeoffer/TakeOfferViewModel.java   |  4 +-
 .../java/io/bitsquare/offer/OfferBook.java    |  3 +-
 .../tasks/BroadcastCreateOfferFeeTx.java      | 89 +++++++++++--------
 .../io/bitsquare/util/taskrunner/Task.java    |  2 +-
 6 files changed, 56 insertions(+), 50 deletions(-)

diff --git a/core/src/main/java/io/bitsquare/btc/FeePolicy.java b/core/src/main/java/io/bitsquare/btc/FeePolicy.java
index c2fed1861b..68e6797b84 100644
--- a/core/src/main/java/io/bitsquare/btc/FeePolicy.java
+++ b/core/src/main/java/io/bitsquare/btc/FeePolicy.java
@@ -33,7 +33,7 @@ public class FeePolicy {
 
     // TODO: Change REGISTRATION_FEE to 0.00001 (See https://github.com/bitsquare/bitsquare/issues/228)
     public static final Coin REGISTRATION_FEE = TX_FEE.add(TX_FEE);
-    public static final Coin CREATE_OFFER_FEE = Coin.valueOf(20000); // 0.0002 BTC
+    public static final Coin CREATE_OFFER_FEE = Coin.valueOf(10000000); // 0.1 BTC
     public static final Coin TAKE_OFFER_FEE = CREATE_OFFER_FEE;
 
     private final BitcoinNetwork bitcoinNetwork;
diff --git a/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewModel.java b/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewModel.java
index 503253748c..ee36572dfb 100644
--- a/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewModel.java
+++ b/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewModel.java
@@ -142,7 +142,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
         dataModel.requestPlaceOfferErrorMessage.set(null);
         dataModel.requestPlaceOfferSuccess.set(false);
 
-        isPlaceOfferButtonDisabled.set(true);
         isPlaceOfferSpinnerVisible.set(true);
 
         dataModel.placeOffer();
@@ -291,9 +290,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
             updateButtonDisableState();
         });
         dataModel.isWalletFunded.addListener((ov, oldValue, newValue) -> {
-            if (newValue) {
-                updateButtonDisableState();
-            }
+            updateButtonDisableState();
         });
 
         // Binding with Bindings.createObjectBinding does not work because of bi-directional binding
@@ -304,7 +301,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
 
         dataModel.requestPlaceOfferErrorMessage.addListener((ov, oldValue, newValue) -> {
             if (newValue != null) {
-                isPlaceOfferButtonDisabled.set(false);
                 isPlaceOfferSpinnerVisible.set(false);
             }
         });
diff --git a/core/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java b/core/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java
index f5f8f48750..661f8d0d31 100644
--- a/core/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java
+++ b/core/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewModel.java
@@ -268,9 +268,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
         });
 
         dataModel.isWalletFunded.addListener((ov, oldValue, newValue) -> {
-            if (newValue) {
-                updateButtonDisableState();
-            }
+            updateButtonDisableState();
         });
 
         // Binding with Bindings.createObjectBinding does not work because of bi-directional binding
diff --git a/core/src/main/java/io/bitsquare/offer/OfferBook.java b/core/src/main/java/io/bitsquare/offer/OfferBook.java
index 3a14d78902..009d0255b3 100644
--- a/core/src/main/java/io/bitsquare/offer/OfferBook.java
+++ b/core/src/main/java/io/bitsquare/offer/OfferBook.java
@@ -49,6 +49,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 public class OfferBook {
 
     private static final Logger log = LoggerFactory.getLogger(OfferBook.class);
+    private static final int POLLING_INTERVAL = 1000;
 
     private final OfferBookService offerBookService;
     private final User user;
@@ -180,7 +181,7 @@ public class OfferBook {
     private void startPolling() {
         addListeners();
         setBankAccount(user.getCurrentBankAccount().get());
-        pollingTimer = Utilities.setInterval(3000, (animationTimer) -> {
+        pollingTimer = Utilities.setInterval(POLLING_INTERVAL, (animationTimer) -> {
             offerBookService.requestInvalidationTimeStampFromDHT(fiatCode);
             return null;
         });
diff --git a/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java b/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java
index 584515ea85..f5b7478fd2 100644
--- a/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java
+++ b/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java
@@ -17,10 +17,13 @@
 
 package io.bitsquare.trade.protocol.placeoffer.tasks;
 
+import io.bitsquare.btc.AddressEntry;
+import io.bitsquare.btc.FeePolicy;
 import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
 import io.bitsquare.util.taskrunner.Task;
 import io.bitsquare.util.taskrunner.TaskRunner;
 
+import org.bitcoinj.core.Coin;
 import org.bitcoinj.core.Transaction;
 
 import com.google.common.util.concurrent.FutureCallback;
@@ -43,53 +46,61 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
 
     @Override
     protected void doRun() {
-        model.getWalletService().broadcastCreateOfferFeeTx(model.getTransaction(), new FutureCallback<Transaction>() {
 
+        Coin totalsNeeded = model.getOffer().getSecurityDeposit().add(FeePolicy.CREATE_OFFER_FEE).add(FeePolicy.TX_FEE);
+        AddressEntry addressEntry = model.getWalletService().getAddressInfoByTradeID(model.getOffer().getId());
+        Coin balance = model.getWalletService().getBalanceForAddress(addressEntry.getAddress());
+        if (balance.compareTo(totalsNeeded) >= 0) {
 
-            @Override
-            public void onSuccess(Transaction transaction) {
-                log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString());
-                if (transaction != null) {
+            model.getWalletService().broadcastCreateOfferFeeTx(model.getTransaction(), new FutureCallback<Transaction>() {
+                @Override
+                public void onSuccess(Transaction transaction) {
+                    log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString());
+                    if (transaction != null) {
 
-                    if (model.getTransaction().getHashAsString() == transaction.getHashAsString()) {
-                        // No tx malleability happened after broadcast (still not in blockchain)
-                        complete();
+                        if (model.getTransaction().getHashAsString() == transaction.getHashAsString()) {
+                            // No tx malleability happened after broadcast (still not in blockchain)
+                            complete();
+                        }
+                        else {
+                            log.warn("Tx malleability happened after broadcast. We publish the changed offer to the DHT again.");
+                            // Tx malleability happened after broadcast. We publish the changed offer to the DHT again.
+                            model.getOfferBookService().removeOffer(model.getOffer(),
+                                    () -> {
+                                        log.info("We store now the changed txID to the offer and add that again.");
+                                        // We store now the changed txID to the offer and add that again.
+                                        model.getOffer().setOfferFeePaymentTxID(transaction.getHashAsString());
+                                        model.getOfferBookService().addOffer(model.getOffer(),
+                                                () -> {
+                                                    complete();
+                                                },
+                                                (message, throwable) -> {
+                                                    log.error("addOffer failed");
+                                                    addOfferFailed = true;
+                                                    failed(throwable);
+                                                });
+                                    },
+                                    (message, throwable) -> {
+                                        log.error("removeOffer failed");
+                                        removeOfferFailed = true;
+                                        failed(throwable);
+                                    });
+                        }
                     }
                     else {
-                        log.warn("Tx malleability happened after broadcast. We publish the changed offer to the DHT again.");
-                        // Tx malleability happened after broadcast. We publish the changed offer to the DHT again.
-                        model.getOfferBookService().removeOffer(model.getOffer(),
-                                () -> {
-                                    log.info("We store now the changed txID to the offer and add that again.");
-                                    // We store now the changed txID to the offer and add that again.
-                                    model.getOffer().setOfferFeePaymentTxID(transaction.getHashAsString());
-                                    model.getOfferBookService().addOffer(model.getOffer(),
-                                            () -> {
-                                                complete();
-                                            },
-                                            (message, throwable) -> {
-                                                log.error("addOffer failed");
-                                                addOfferFailed = true;
-                                                failed(throwable);
-                                            });
-                                },
-                                (message, throwable) -> {
-                                    log.error("removeOffer failed");
-                                    removeOfferFailed = true;
-                                    failed(throwable);
-                                });
+                        failed("Fault reason: Transaction = null.");
                     }
                 }
-                else {
-                    failed("Fault reason: Transaction = null.");
-                }
-            }
 
-            @Override
-            public void onFailure(Throwable t) {
-                failed(t);
-            }
-        });
+                @Override
+                public void onFailure(Throwable t) {
+                    failed(t);
+                }
+            });
+        }
+        else {
+            failed("Not enough balance for placing the offer.");
+        }
     }
 
     protected void applyErrorState() {
diff --git a/core/src/main/java/io/bitsquare/util/taskrunner/Task.java b/core/src/main/java/io/bitsquare/util/taskrunner/Task.java
index aecfd9b293..4eace2fc8e 100644
--- a/core/src/main/java/io/bitsquare/util/taskrunner/Task.java
+++ b/core/src/main/java/io/bitsquare/util/taskrunner/Task.java
@@ -65,7 +65,7 @@ public abstract class Task<T extends SharedModel> {
     }
 
     protected void appendExceptionToErrorMessage(Throwable t) {
-        errorMessage += "\n Exception message: " + t.getMessage();
+        errorMessage += "\nException message: " + t.getMessage();
     }
 
     protected void complete() {