Fixed state handling in views

This commit is contained in:
Manfred Karrer 2015-03-26 11:51:42 +01:00
parent 9936dca851
commit ccd2e6b676
10 changed files with 235 additions and 168 deletions

View file

@ -78,7 +78,7 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
case FAILED:
return "Failed";
case PENDING:
throw new RuntimeException("Wrong state: " + lifeCycleState);
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
}
}
else if (lifeCycleState instanceof OffererTrade.OffererLifeCycleState) {
@ -91,11 +91,10 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
return "Failed";
case OPEN_OFFER:
case PENDING:
throw new RuntimeException("Wrong state: " + lifeCycleState);
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
}
}
return "Undefined";
throw new RuntimeException("That must not happen. We got no defined state.");
}
else {
return "";

View file

@ -17,22 +17,19 @@
package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.inject.Inject;
@ -44,13 +41,10 @@ import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -65,28 +59,27 @@ class PendingTradesDataModel implements Activatable, DataModel {
private PendingTradesListItem selectedItem;
private boolean isOfferer;
private Trade closedTrade;
private final ChangeListener<Trade.ProcessState> tradeStateChangeListener;
private final ListChangeListener<Trade> tradesListChangeListener;
final StringProperty txId = new SimpleStringProperty();
final ObjectProperty<Trade.ProcessState> tradeState = new SimpleObjectProperty<>();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<TakerTrade.TakerProcessState> takerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<OffererTrade.OffererProcessState> offererProcessState = new SimpleObjectProperty<>();
@Inject
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) {
this.tradeManager = tradeManager;
this.walletService = walletService;
this.user = user;
tradeStateChangeListener = (ov, oldValue, newValue) -> tradeState.set(newValue);
tradesListChangeListener = change -> applyList();
tradesListChangeListener = change -> onListChanged();
}
@Override
public void activate() {
applyList();
onListChanged();
tradeManager.getPendingTrades().addListener(tradesListChangeListener);
if (list.size() > 0) {
@ -98,10 +91,10 @@ class PendingTradesDataModel implements Activatable, DataModel {
@Override
public void deactivate() {
tradeManager.getPendingTrades().removeListener(tradesListChangeListener);
cleanUpSelectedTrade();
removeListenerFromSelectedTrade();
}
private void applyList() {
private void onListChanged() {
list.clear();
list.addAll(tradeManager.getPendingTrades().stream().map(PendingTradesListItem::new).collect(Collectors.toList()));
@ -116,7 +109,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
void selectTrade(PendingTradesListItem item) {
// clean up previous selectedItem
cleanUpSelectedTrade();
removeListenerFromSelectedTrade();
selectedItem = item;
@ -124,8 +117,11 @@ class PendingTradesDataModel implements Activatable, DataModel {
isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
Trade trade = getTrade();
trade.processStateProperty().addListener(tradeStateChangeListener);
tradeState.set(trade.processStateProperty().get());
if (trade instanceof TakerTrade)
takerProcessState.bind(((TakerTrade) trade).processStateProperty());
else
offererProcessState.bind(((OffererTrade) trade).processStateProperty());
log.trace("selectTrade trade.stateProperty().get() " + trade.processStateProperty().get());
if (trade.getDepositTx() != null)
@ -133,7 +129,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
else {
txId.set(null);
tradeState.set(null);
}
}
@ -146,34 +141,14 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
void withdraw(String toAddress) {
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) {
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
tradeManager.requestWithdraw(toAddress,
getTrade(),
() -> log.debug("requestWithdraw was successful"),
(errorMessage, throwable) -> {
log.error(errorMessage);
Popups.openExceptionPopup(throwable);
});
if (closedTrade != null) {
list.removeIf(e -> e.getTrade().getId().equals(closedTrade.getId()));
}
}
}
@Override
public void onFailure(@NotNull Throwable t) {
log.debug("onWithdraw onFailure");
}
};
AddressEntry addressEntry = walletService.getAddressEntry(getTrade().getId());
String fromAddress = addressEntry.getAddressString();
try {
walletService.sendFunds(fromAddress, toAddress, getAmountToWithdraw(), callback);
} catch (AddressFormatException | InsufficientMoneyException e) {
e.printStackTrace();
log.error(e.getMessage());
}
tradeManager.onWithdrawAtTradeCompleted(getTrade());
/*
Action response = Popups.openConfirmPopup(
@ -203,7 +178,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
}*/
}
ObservableList<PendingTradesListItem> getList() {
return list;
}
@ -232,32 +206,36 @@ class PendingTradesDataModel implements Activatable, DataModel {
return selectedItem.getTrade().getOffer().getCurrencyCode();
}
Throwable getTradeException() {
return getTrade().getThrowable();
}
String getErrorMessage() {
return getTrade().getErrorMessage();
}
public Offer.Direction getDirection(Offer offer) {
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
offer.getDirection() : offer.getMirroredDirection();
}
Coin getAmountToWithdraw() {
AddressEntry addressEntry = walletService.getAddressEntry(getTrade().getId());
log.debug("trade id " + getTrade().getId());
log.debug("getAddressString " + addressEntry.getAddressString());
log.debug("funds " + walletService.getBalanceForAddress(addressEntry.getAddress()).subtract(FeePolicy
.TX_FEE).toString());
// return walletService.getBalanceForAddress(addressEntry.getAddress()).subtract(FeePolicy.TX_FEE);
// TODO handle overpaid securityDeposit
if (isOfferer())
return getTrade().getTradeAmount().add(getTrade().getOffer().getSecurityDeposit());
else
return getTrade().getSecurityDeposit();
}
private void cleanUpSelectedTrade() {
private void removeListenerFromSelectedTrade() {
if (selectedItem != null) {
selectedItem.getTrade().processStateProperty().removeListener(tradeStateChangeListener);
Trade trade = selectedItem.getTrade();
if (trade instanceof TakerTrade)
takerProcessState.unbind();
else
offererProcessState.unbind();
}
}
public Coin getAmountToWithdraw() {
Trade trade = selectedItem.getTrade();
Coin amountToWithdraw = trade.getSecurityDeposit();
if (trade instanceof OffererTrade)
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
return amountToWithdraw;
}
}

View file

@ -85,8 +85,8 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
private ChangeListener<Number> selectedIndexChangeListener;
private ListChangeListener<PendingTradesListItem> listChangeListener;
private ChangeListener<String> txIdChangeListener;
private ChangeListener<PendingTradesViewModel.State> offererStateChangeListener;
private ChangeListener<PendingTradesViewModel.State> takerStateChangeListener;
private ChangeListener<PendingTradesViewModel.ViewState> offererStateChangeListener;
private ChangeListener<PendingTradesViewModel.ViewState> takerStateChangeListener;
private final Navigation navigation;
private ChangeListener<Boolean> focusedPropertyListener;
@ -170,8 +170,8 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
public void doDeactivate() {
model.getList().removeListener(listChangeListener);
model.txId.removeListener(txIdChangeListener);
model.state.removeListener(offererStateChangeListener);
model.state.removeListener(takerStateChangeListener);
model.viewState.removeListener(offererStateChangeListener);
model.viewState.removeListener(takerStateChangeListener);
model.selectedIndex.removeListener(selectedIndexChangeListener);
table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener);
@ -258,8 +258,8 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
processBar.setProcessStepItems(items);
}
model.state.addListener(offererStateChangeListener);
applyOffererState(model.state.get());
model.viewState.addListener(offererStateChangeListener);
applyOffererState(model.viewState.get());
}
private void setupScreenForTaker() {
@ -273,18 +273,18 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
processBar.setProcessStepItems(items);
}
model.state.addListener(takerStateChangeListener);
applyTakerState(model.state.get());
model.viewState.addListener(takerStateChangeListener);
applyTakerState(model.viewState.get());
}
private void applyOffererState(PendingTradesViewModel.State state) {
private void applyOffererState(PendingTradesViewModel.ViewState viewState) {
setPaymentsControlsVisible(false);
setSummaryControlsVisible(false);
log.debug("applyOffererState " + state);
log.debug("applyOffererState " + viewState);
processBar.reset();
if (state != null) {
switch (state) {
if (viewState != null) {
switch (viewState) {
case OFFERER_BUYER_WAIT_TX_CONF:
processBar.setSelectedIndex(0);
@ -347,21 +347,27 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
withdrawAmountTextField.setText(model.getAmountToWithdraw());
break;
case MESSAGE_SENDING_FAILED:
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
break;
case EXCEPTION:
Popups.openExceptionPopup(model.getTradeException());
break;
}
}
}
private void applyTakerState(PendingTradesViewModel.State state) {
private void applyTakerState(PendingTradesViewModel.ViewState viewState) {
confirmPaymentReceiptButton.setVisible(false);
confirmPaymentReceiptButton.setManaged(false);
setSummaryControlsVisible(false);
processBar.reset();
log.debug("applyTakerState " + state);
log.debug("applyTakerState " + viewState);
if (state != null) {
switch (state) {
if (viewState != null) {
switch (viewState) {
case TAKER_SELLER_WAIT_TX_CONF:
processBar.setSelectedIndex(0);
@ -422,6 +428,12 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
withdrawAmountTextField.setText(model.getAmountToWithdraw());
break;
case MESSAGE_SENDING_FAILED:
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
break;
case EXCEPTION:
Popups.openExceptionPopup(model.getTradeException());
break;
}
}
}

View file

@ -25,7 +25,6 @@ import io.bitsquare.gui.util.validation.BtcAddressValidator;
import io.bitsquare.locale.BSResources;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
@ -51,7 +50,7 @@ import org.slf4j.LoggerFactory;
class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataModel> implements ViewModel {
private static final Logger log = LoggerFactory.getLogger(PendingTradesViewModel.class);
enum State {
enum ViewState {
TAKER_SELLER_WAIT_TX_CONF,
TAKER_SELLER_WAIT_PAYMENT_STARTED,
TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT,
@ -61,16 +60,20 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
OFFERER_BUYER_START_PAYMENT,
OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED,
OFFERER_BUYER_COMPLETED,
MESSAGE_SENDING_FAILED,
EXCEPTION
}
private final BSFormatter formatter;
private final InvalidationListener stateChangeListener;
private final InvalidationListener takerStateListener;
private final InvalidationListener offererStateListener;
private final BtcAddressValidator btcAddressValidator;
final StringProperty txId = new SimpleStringProperty();
final ObjectProperty<State> state = new SimpleObjectProperty<>();
final BooleanProperty withdrawalButtonDisable = new SimpleBooleanProperty(true);
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<ViewState> viewState = new SimpleObjectProperty<>();
@Inject
@ -80,7 +83,8 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
this.formatter = formatter;
this.btcAddressValidator = btcAddressValidator;
this.stateChangeListener = (ov) -> updateState();
this.takerStateListener = (ov) -> updateTakerState();
this.offererStateListener = (ov) -> updateOffererState();
}
@Override
@ -88,8 +92,11 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
txId.bind(dataModel.txId);
selectedIndex.bind(dataModel.selectedIndex);
dataModel.tradeState.addListener(stateChangeListener);
updateState();
dataModel.takerProcessState.addListener(takerStateListener);
dataModel.offererProcessState.addListener(offererStateListener);
updateTakerState();
updateOffererState();
}
@Override
@ -97,13 +104,15 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
txId.unbind();
selectedIndex.unbind();
dataModel.tradeState.removeListener(stateChangeListener);
dataModel.takerProcessState.removeListener(takerStateListener);
dataModel.offererProcessState.removeListener(offererStateListener);
}
void selectTrade(PendingTradesListItem item) {
dataModel.selectTrade(item);
updateState();
/* updateTakerState();
updateOffererState();*/
}
void fiatPaymentStarted() {
@ -123,7 +132,7 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
}
String getAmountToWithdraw() {
return formatter.formatCoinWithCode(dataModel.getAmountToWithdraw()); //.subtract(FeePolicy.TX_FEE));
return formatter.formatCoinWithCode(dataModel.getAmountToWithdraw());
}
ObservableList<PendingTradesListItem> getList() {
@ -218,63 +227,88 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
return btcAddressValidator;
}
Throwable getTradeException() {
return dataModel.getTradeException();
}
private void updateState() {
Trade.ProcessState processState = dataModel.tradeState.get();
log.trace("tradeState " + processState);
String getErrorMessage() {
return dataModel.getErrorMessage();
}
private void updateTakerState() {
TakerTrade.TakerProcessState processState = dataModel.takerProcessState.get();
log.debug("updateTakerState " + processState);
if (processState != null) {
if (processState instanceof TakerTrade.TakerProcessState) {
switch ((TakerTrade.TakerProcessState) processState) {
switch (processState) {
case TAKE_OFFER_FEE_TX_CREATED:
break;
case TAKE_OFFER_FEE_PUBLISHED:
break;
case TAKE_OFFER_FEE_PUBLISH_FAILED:
break;
case DEPOSIT_PUBLISHED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF);
viewState.set(ViewState.TAKER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_START_PAYMENT :
State.TAKER_SELLER_WAIT_PAYMENT_STARTED);
viewState.set(ViewState.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break;
case FIAT_PAYMENT_STARTED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED :
State.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
viewState.set(ViewState.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case FIAT_PAYMENT_RECEIVED:
viewState.set(ViewState.TAKER_SELLER_COMPLETED);
break;
case PAYOUT_PUBLISHED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_COMPLETED : State.TAKER_SELLER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
// TODO error states not implemented yet
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled state " + processState);
log.warn("unhandled processState " + processState);
break;
}
}
else if (processState instanceof OffererTrade.OffererProcessState) {
switch ((OffererTrade.OffererProcessState) processState) {
case DEPOSIT_PUBLISHED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_START_PAYMENT :
State.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break;
case FIAT_PAYMENT_STARTED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED :
State.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case PAYOUT_PUBLISHED:
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_COMPLETED : State.TAKER_SELLER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
// TODO error states not implemented yet
break;
default:
log.warn("unhandled state " + processState);
break;
}
}
}
else {
state.set(null);
}
}
private void updateOffererState() {
OffererTrade.OffererProcessState processState = dataModel.offererProcessState.get();
log.debug("updateOffererState " + processState);
if (processState != null) {
switch (processState) {
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.OFFERER_BUYER_START_PAYMENT);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
break;
case PAYOUT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled viewState " + processState);
break;
}
}
}
}

View file

@ -34,6 +34,7 @@
package io.bitsquare.storage;
import io.bitsquare.gui.components.Popups;
import org.bitcoinj.core.Utils;

View file

@ -17,7 +17,7 @@
package io.bitsquare.storage;
import io.bitsquare.gui.components.Popups;
import com.google.common.base.Throwables;
import java.io.File;
import java.io.FileNotFoundException;
@ -132,7 +132,7 @@ public class Storage<T extends Serializable> {
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
log.error(e.getMessage());
Popups.openErrorPopup("An exception occurred at reading data from disc.", e.getMessage());
Throwables.propagate(e);
}
return null;

View file

@ -64,7 +64,7 @@ public class OffererTrade extends Trade implements Serializable {
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
UNSPECIFIC_FAULT
EXCEPTION
}
protected OffererProcessState processState;
@ -104,7 +104,7 @@ public class OffererTrade extends Trade implements Serializable {
processStateProperty.set(processState);
switch (processState) {
case UNSPECIFIC_FAULT:
case EXCEPTION:
disposeProtocol();
setLifeCycleState(OffererLifeCycleState.FAILED);
break;

View file

@ -69,8 +69,8 @@ abstract public class Trade implements Serializable {
transient protected String errorMessage;
transient protected Throwable throwable;
transient protected ObjectProperty<Coin> tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
transient protected ObjectProperty<Fiat> tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
transient protected ObjectProperty<Coin> tradeAmountProperty;
transient protected ObjectProperty<Fiat> tradeVolumeProperty;
///////////////////////////////////////////////////////////////////////////////////////////
@ -80,6 +80,8 @@ abstract public class Trade implements Serializable {
public Trade(Offer offer) {
this.offer = offer;
date = new Date();
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume()); // cannot be set before offer is set
}
// Serialized object does not create our transient objects

View file

@ -18,9 +18,11 @@
package io.bitsquare.trade;
import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.crypto.EncryptionService;
import io.bitsquare.crypto.SignatureService;
@ -47,9 +49,14 @@ import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
import io.bitsquare.user.AccountSettings;
import io.bitsquare.user.User;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.utils.Fiat;
import com.google.common.util.concurrent.FutureCallback;
import java.io.File;
import java.util.HashMap;
@ -62,6 +69,8 @@ import javax.inject.Named;
import javafx.collections.ObservableList;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -259,7 +268,20 @@ public class TradeManager {
((TakerTrade) trade).onFiatPaymentReceived();
}
public void onWithdrawAtTradeCompleted(Trade trade) {
public void requestWithdraw(String toAddress, Trade trade, ResultHandler resultHandler, FaultHandler faultHandler) {
AddressEntry addressEntry = walletService.getAddressEntry(trade.getId());
String fromAddress = addressEntry.getAddressString();
// TODO handle overpaid securityDeposit
Coin amountToWithdraw = trade.getSecurityDeposit();
if (trade instanceof OffererTrade)
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) {
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
if (trade instanceof OffererTrade)
((OffererTrade) trade).setLifeCycleState(OffererTrade.OffererLifeCycleState.COMPLETED);
else
@ -267,6 +289,25 @@ public class TradeManager {
pendingTrades.remove(trade);
closedTrades.add(trade);
resultHandler.handleResult();
}
}
@Override
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
faultHandler.handleFault("An exception occurred at requestWithdraw (onFailure).", t);
}
};
try {
walletService.sendFunds(fromAddress, toAddress, amountToWithdraw, callback);
} catch (AddressFormatException | InsufficientMoneyException e) {
e.printStackTrace();
log.error(e.getMessage());
faultHandler.handleFault("An exception occurred at requestWithdraw.", e);
}
}
@ -437,5 +478,4 @@ public class TradeManager {
log.error(fault.getMessage());
});
}
}

View file

@ -19,9 +19,10 @@ package io.bitsquare.user;
import io.bitsquare.crypto.EncryptionService;
import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.storage.Storage;
import com.google.common.base.Throwables;
import java.io.Serializable;
import java.security.KeyPair;
@ -94,7 +95,7 @@ public class User implements Serializable {
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
log.error(e.getMessage());
Popups.openExceptionPopup(e);
Throwables.propagate(e);
}
}
storage.save();