mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-23 07:00:49 -04:00
Separate open offer
This commit is contained in:
parent
37f228b049
commit
95e23dc8a9
69 changed files with 976 additions and 546 deletions
|
@ -37,7 +37,7 @@ public class FiatAccount implements Serializable {
|
||||||
public static final long WEEK_IN_BLOCKS = DAY_IN_BLOCKS * 7;
|
public static final long WEEK_IN_BLOCKS = DAY_IN_BLOCKS * 7;
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
IRC("", "", 0),
|
IRC("", "", 2),
|
||||||
SEPA("IBAN", "BIC", WEEK_IN_BLOCKS),
|
SEPA("IBAN", "BIC", WEEK_IN_BLOCKS),
|
||||||
WIRE("primary ID", "secondary ID", WEEK_IN_BLOCKS),
|
WIRE("primary ID", "secondary ID", WEEK_IN_BLOCKS),
|
||||||
INTERNATIONAL("primary ID", "secondary ID", 2 * WEEK_IN_BLOCKS),
|
INTERNATIONAL("primary ID", "secondary ID", 2 * WEEK_IN_BLOCKS),
|
||||||
|
|
|
@ -252,11 +252,13 @@ public class BootstrappedPeerBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bootstrap() {
|
private void bootstrap() {
|
||||||
|
log.trace("start bootstrap");
|
||||||
FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(getBootstrapAddress()).start();
|
FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(getBootstrapAddress()).start();
|
||||||
futureBootstrap.addListener(new BaseFutureListener<BaseFuture>() {
|
futureBootstrap.addListener(new BaseFutureListener<BaseFuture>() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(BaseFuture future) throws Exception {
|
public void operationComplete(BaseFuture future) throws Exception {
|
||||||
if (futureBootstrap.isSuccess()) {
|
if (futureBootstrap.isSuccess()) {
|
||||||
|
log.trace("bootstrap complete");
|
||||||
settableFuture.set(peerDHT);
|
settableFuture.set(peerDHT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -22,9 +22,9 @@ import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.crypto.KeyRing;
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.crypto.PubKeyRing;
|
import io.bitsquare.crypto.PubKeyRing;
|
||||||
import io.bitsquare.crypto.SealedAndSignedMessage;
|
import io.bitsquare.crypto.SealedAndSignedMessage;
|
||||||
import io.bitsquare.offer.OfferBookService;
|
|
||||||
import io.bitsquare.p2p.MailboxMessagesResultHandler;
|
import io.bitsquare.p2p.MailboxMessagesResultHandler;
|
||||||
import io.bitsquare.p2p.MailboxService;
|
import io.bitsquare.p2p.MailboxService;
|
||||||
|
import io.bitsquare.trade.offer.OfferBookService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
package io.bitsquare.trade;
|
package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.trade.BuyerAsOffererProtocol;
|
import io.bitsquare.trade.protocol.trade.BuyerAsOffererProtocol;
|
||||||
import io.bitsquare.trade.protocol.trade.BuyerProtocol;
|
import io.bitsquare.trade.protocol.trade.BuyerProtocol;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ public class BuyerAsOffererTrade extends OffererTrade implements BuyerTrade, Ser
|
||||||
// Constructor, initialization
|
// Constructor, initialization
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public BuyerAsOffererTrade(Offer offer, Storage<? extends TradeList> storage) {
|
public BuyerAsOffererTrade(Offer offer, Storage<? extends TradableList> storage) {
|
||||||
super(offer, storage);
|
super(offer, storage);
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
package io.bitsquare.trade;
|
package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.trade.BuyerAsTakerProtocol;
|
import io.bitsquare.trade.protocol.trade.BuyerAsTakerProtocol;
|
||||||
import io.bitsquare.trade.protocol.trade.BuyerProtocol;
|
import io.bitsquare.trade.protocol.trade.BuyerProtocol;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class BuyerAsTakerTrade extends TakerTrade implements BuyerTrade, Seriali
|
||||||
// Constructor, initialization
|
// Constructor, initialization
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public BuyerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradeList> storage) {
|
public BuyerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) {
|
||||||
super(offer, tradeAmount, tradingPeer, storage);
|
super(offer, tradeAmount, tradingPeer, storage);
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.crypto.PubKeyRing;
|
import io.bitsquare.crypto.PubKeyRing;
|
||||||
import io.bitsquare.fiat.FiatAccount;
|
import io.bitsquare.fiat.FiatAccount;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,11 @@
|
||||||
|
|
||||||
package io.bitsquare.trade;
|
package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
import io.bitsquare.trade.protocol.trade.OffererProtocol;
|
||||||
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
import io.bitsquare.trade.states.OffererTradeState;
|
import io.bitsquare.trade.states.OffererTradeState;
|
||||||
import io.bitsquare.trade.states.TradeState;
|
import io.bitsquare.trade.states.TradeState;
|
||||||
|
|
||||||
|
@ -33,7 +36,7 @@ public abstract class OffererTrade extends Trade implements Serializable {
|
||||||
|
|
||||||
transient private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererTrade.class);
|
transient private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererTrade.class);
|
||||||
|
|
||||||
public OffererTrade(Offer offer, Storage<? extends TradeList> storage) {
|
public OffererTrade(Offer offer, Storage<? extends TradableList> storage) {
|
||||||
super(offer, storage);
|
super(offer, storage);
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
}
|
}
|
||||||
|
@ -41,10 +44,14 @@ public abstract class OffererTrade extends Trade implements Serializable {
|
||||||
@Override
|
@Override
|
||||||
protected void initStates() {
|
protected void initStates() {
|
||||||
processState = OffererTradeState.ProcessState.UNDEFINED;
|
processState = OffererTradeState.ProcessState.UNDEFINED;
|
||||||
lifeCycleState = OffererTradeState.LifeCycleState.OFFER_OPEN;
|
lifeCycleState = Trade.LifeCycleState.PREPARATION;
|
||||||
initStateProperties();
|
initStateProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleTakeOfferRequest(TradeMessage message, Peer taker) {
|
||||||
|
((OffererProtocol) tradeProtocol).handleTakeOfferRequest(message, taker);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Setter for Mutable objects
|
// Setter for Mutable objects
|
||||||
|
@ -57,16 +64,16 @@ public abstract class OffererTrade extends Trade implements Serializable {
|
||||||
switch ((OffererTradeState.ProcessState) processState) {
|
switch ((OffererTradeState.ProcessState) processState) {
|
||||||
case EXCEPTION:
|
case EXCEPTION:
|
||||||
disposeProtocol();
|
disposeProtocol();
|
||||||
setLifeCycleState(OffererTradeState.LifeCycleState.FAILED);
|
setLifeCycleState(Trade.LifeCycleState.FAILED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLifeCycleState(TradeState.LifeCycleState lifeCycleState) {
|
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
|
||||||
super.setLifeCycleState(lifeCycleState);
|
super.setLifeCycleState(lifeCycleState);
|
||||||
|
|
||||||
switch ((OffererTradeState.LifeCycleState) lifeCycleState) {
|
switch (lifeCycleState) {
|
||||||
case FAILED:
|
case FAILED:
|
||||||
disposeProtocol();
|
disposeProtocol();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
package io.bitsquare.trade;
|
package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.trade.SellerAsOffererProtocol;
|
import io.bitsquare.trade.protocol.trade.SellerAsOffererProtocol;
|
||||||
import io.bitsquare.trade.protocol.trade.SellerProtocol;
|
import io.bitsquare.trade.protocol.trade.SellerProtocol;
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ public class SellerAsOffererTrade extends OffererTrade implements SellerTrade, S
|
||||||
// Constructor, initialization
|
// Constructor, initialization
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public SellerAsOffererTrade(Offer offer, Storage<? extends TradeList> storage) {
|
public SellerAsOffererTrade(Offer offer, Storage<? extends TradableList> storage) {
|
||||||
super(offer, storage);
|
super(offer, storage);
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
package io.bitsquare.trade;
|
package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.trade.SellerAsTakerProtocol;
|
import io.bitsquare.trade.protocol.trade.SellerAsTakerProtocol;
|
||||||
import io.bitsquare.trade.protocol.trade.SellerProtocol;
|
import io.bitsquare.trade.protocol.trade.SellerProtocol;
|
||||||
import io.bitsquare.trade.states.TakerTradeState;
|
import io.bitsquare.trade.states.TakerTradeState;
|
||||||
|
@ -43,7 +43,7 @@ public class SellerAsTakerTrade extends TakerTrade implements SellerTrade, Seria
|
||||||
// Constructor, initialization
|
// Constructor, initialization
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public SellerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradeList> storage) {
|
public SellerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) {
|
||||||
super(offer, tradeAmount, tradingPeer, storage);
|
super(offer, tradeAmount, tradingPeer, storage);
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
package io.bitsquare.trade;
|
package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.trade.TakerProtocol;
|
import io.bitsquare.trade.protocol.trade.TakerProtocol;
|
||||||
import io.bitsquare.trade.states.TakerTradeState;
|
import io.bitsquare.trade.states.TakerTradeState;
|
||||||
import io.bitsquare.trade.states.TradeState;
|
import io.bitsquare.trade.states.TradeState;
|
||||||
|
@ -37,7 +37,7 @@ public abstract class TakerTrade extends Trade implements Serializable {
|
||||||
|
|
||||||
transient private static final Logger log = LoggerFactory.getLogger(BuyerAsTakerTrade.class);
|
transient private static final Logger log = LoggerFactory.getLogger(BuyerAsTakerTrade.class);
|
||||||
|
|
||||||
public TakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradeList> storage) {
|
public TakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) {
|
||||||
super(offer, tradeAmount, tradingPeer, storage);
|
super(offer, tradeAmount, tradingPeer, storage);
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public abstract class TakerTrade extends Trade implements Serializable {
|
||||||
@Override
|
@Override
|
||||||
protected void initStates() {
|
protected void initStates() {
|
||||||
processState = TakerTradeState.ProcessState.UNDEFINED;
|
processState = TakerTradeState.ProcessState.UNDEFINED;
|
||||||
lifeCycleState = TakerTradeState.LifeCycleState.PENDING;
|
lifeCycleState = Trade.LifeCycleState.PENDING;
|
||||||
initStateProperties();
|
initStateProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,16 +66,16 @@ public abstract class TakerTrade extends Trade implements Serializable {
|
||||||
switch ((TakerTradeState.ProcessState) processState) {
|
switch ((TakerTradeState.ProcessState) processState) {
|
||||||
case EXCEPTION:
|
case EXCEPTION:
|
||||||
disposeProtocol();
|
disposeProtocol();
|
||||||
setLifeCycleState(TakerTradeState.LifeCycleState.FAILED);
|
setLifeCycleState(Trade.LifeCycleState.FAILED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLifeCycleState(TradeState.LifeCycleState lifeCycleState) {
|
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
|
||||||
super.setLifeCycleState(lifeCycleState);
|
super.setLifeCycleState(lifeCycleState);
|
||||||
|
|
||||||
switch ((TakerTradeState.LifeCycleState) lifeCycleState) {
|
switch (lifeCycleState) {
|
||||||
case FAILED:
|
case FAILED:
|
||||||
disposeProtocol();
|
disposeProtocol();
|
||||||
break;
|
break;
|
||||||
|
|
32
core/src/main/java/io/bitsquare/trade/Tradable.java
Normal file
32
core/src/main/java/io/bitsquare/trade/Tradable.java
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface Tradable extends Serializable {
|
||||||
|
Offer getOffer();
|
||||||
|
|
||||||
|
Date getDate();
|
||||||
|
|
||||||
|
String getId();
|
||||||
|
}
|
|
@ -31,13 +31,13 @@ import javafx.collections.ObservableList;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class TradeList<T> extends ArrayList<T> implements Serializable {
|
public class TradableList<T extends Tradable> extends ArrayList<T> implements Serializable {
|
||||||
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
transient private static final Logger log = LoggerFactory.getLogger(TradeList.class);
|
transient private static final Logger log = LoggerFactory.getLogger(TradableList.class);
|
||||||
|
|
||||||
transient final private Storage<TradeList> storage;
|
transient final private Storage<TradableList<T>> storage;
|
||||||
// Use getObservableList() also class locally, to be sure that object exists in case we use the object as deserialized form
|
// Use getObservableList() also class locally, to be sure that object exists in case we use the object as deserialized form
|
||||||
transient private ObservableList<T> observableList;
|
transient private ObservableList<T> observableList;
|
||||||
|
|
||||||
|
@ -47,11 +47,12 @@ public class TradeList<T> extends ArrayList<T> implements Serializable {
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public TradeList(Storage<TradeList> storage, String fileName) {
|
public TradableList(Storage<TradableList<T>> storage, String fileName) {
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
|
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
|
|
||||||
TradeList persisted = storage.initAndGetPersisted(this, fileName);
|
TradableList persisted = storage.initAndGetPersisted(this, fileName);
|
||||||
if (persisted != null) {
|
if (persisted != null) {
|
||||||
this.addAll(persisted);
|
this.addAll(persisted);
|
||||||
}
|
}
|
||||||
|
@ -64,17 +65,17 @@ public class TradeList<T> extends ArrayList<T> implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(T trade) {
|
public boolean add(T tradable) {
|
||||||
boolean result = super.add(trade);
|
boolean result = super.add(tradable);
|
||||||
getObservableList().add(trade);
|
getObservableList().add(tradable);
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(Object trade) {
|
public boolean remove(Object tradable) {
|
||||||
boolean result = super.remove(trade);
|
boolean result = super.remove(tradable);
|
||||||
getObservableList().remove(trade);
|
getObservableList().remove(tradable);
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
|
@ -25,11 +25,11 @@ import io.bitsquare.common.taskrunner.Model;
|
||||||
import io.bitsquare.crypto.CryptoService;
|
import io.bitsquare.crypto.CryptoService;
|
||||||
import io.bitsquare.crypto.KeyRing;
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.crypto.MessageWithPubKey;
|
import io.bitsquare.crypto.MessageWithPubKey;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.AddressService;
|
import io.bitsquare.p2p.AddressService;
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.trade.ProcessModel;
|
import io.bitsquare.trade.protocol.trade.ProcessModel;
|
||||||
import io.bitsquare.trade.protocol.trade.TradeProtocol;
|
import io.bitsquare.trade.protocol.trade.TradeProtocol;
|
||||||
import io.bitsquare.trade.states.TradeState;
|
import io.bitsquare.trade.states.TradeState;
|
||||||
|
@ -66,12 +66,19 @@ import org.slf4j.LoggerFactory;
|
||||||
* Holds all data which are relevant to the trade, but not those which are only needed in the trade process as shared data between tasks. Those data are
|
* Holds all data which are relevant to the trade, but not those which are only needed in the trade process as shared data between tasks. Those data are
|
||||||
* stored in the task model.
|
* stored in the task model.
|
||||||
*/
|
*/
|
||||||
abstract public class Trade implements Model, Serializable {
|
abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private transient static final Logger log = LoggerFactory.getLogger(Trade.class);
|
private transient static final Logger log = LoggerFactory.getLogger(Trade.class);
|
||||||
|
|
||||||
|
public enum LifeCycleState {
|
||||||
|
PREPARATION,
|
||||||
|
PENDING,
|
||||||
|
COMPLETED,
|
||||||
|
FAILED
|
||||||
|
}
|
||||||
|
|
||||||
// Mutable
|
// Mutable
|
||||||
private Coin tradeAmount;
|
private Coin tradeAmount;
|
||||||
private Peer tradingPeer;
|
private Peer tradingPeer;
|
||||||
|
@ -85,9 +92,9 @@ abstract public class Trade implements Model, Serializable {
|
||||||
|
|
||||||
// Transient/Immutable
|
// Transient/Immutable
|
||||||
private transient ObjectProperty<TradeState.ProcessState> processStateProperty;
|
private transient ObjectProperty<TradeState.ProcessState> processStateProperty;
|
||||||
private transient ObjectProperty<TradeState.LifeCycleState> lifeCycleStateProperty;
|
private transient ObjectProperty<Trade.LifeCycleState> lifeCycleStateProperty;
|
||||||
// Trades are saved in the TradeList
|
// Trades are saved in the TradeList
|
||||||
transient private Storage<? extends TradeList> storage;
|
transient private Storage<? extends TradableList> storage;
|
||||||
transient protected TradeProtocol tradeProtocol;
|
transient protected TradeProtocol tradeProtocol;
|
||||||
|
|
||||||
// Immutable
|
// Immutable
|
||||||
|
@ -99,7 +106,7 @@ abstract public class Trade implements Model, Serializable {
|
||||||
private MessageWithPubKey messageWithPubKey;
|
private MessageWithPubKey messageWithPubKey;
|
||||||
private Date takeOfferDate;
|
private Date takeOfferDate;
|
||||||
protected TradeState.ProcessState processState;
|
protected TradeState.ProcessState processState;
|
||||||
protected TradeState.LifeCycleState lifeCycleState;
|
protected Trade.LifeCycleState lifeCycleState;
|
||||||
private Transaction depositTx;
|
private Transaction depositTx;
|
||||||
private Contract contract;
|
private Contract contract;
|
||||||
private String contractAsJson;
|
private String contractAsJson;
|
||||||
|
@ -117,7 +124,7 @@ abstract public class Trade implements Model, Serializable {
|
||||||
// Constructor, initialization
|
// Constructor, initialization
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
protected Trade(Offer offer, Storage<? extends TradeList> storage) {
|
protected Trade(Offer offer, Storage<? extends TradableList> storage) {
|
||||||
log.trace("Created by constructor");
|
log.trace("Created by constructor");
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
|
@ -135,7 +142,7 @@ abstract public class Trade implements Model, Serializable {
|
||||||
|
|
||||||
// taker
|
// taker
|
||||||
protected Trade(Offer offer, Coin tradeAmount, Peer tradingPeer,
|
protected Trade(Offer offer, Coin tradeAmount, Peer tradingPeer,
|
||||||
Storage<? extends TradeList> storage) {
|
Storage<? extends TradableList> storage) {
|
||||||
|
|
||||||
this(offer, storage);
|
this(offer, storage);
|
||||||
this.tradeAmount = tradeAmount;
|
this.tradeAmount = tradeAmount;
|
||||||
|
@ -227,7 +234,7 @@ abstract public class Trade implements Model, Serializable {
|
||||||
this.messageWithPubKey = messageWithPubKey;
|
this.messageWithPubKey = messageWithPubKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStorage(Storage<? extends TradeList> storage) {
|
public void setStorage(Storage<? extends TradableList> storage) {
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +244,7 @@ abstract public class Trade implements Model, Serializable {
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLifeCycleState(TradeState.LifeCycleState lifeCycleState) {
|
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
|
||||||
this.lifeCycleState = lifeCycleState;
|
this.lifeCycleState = lifeCycleState;
|
||||||
lifeCycleStateProperty.set(lifeCycleState);
|
lifeCycleStateProperty.set(lifeCycleState);
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
|
@ -302,7 +309,7 @@ abstract public class Trade implements Model, Serializable {
|
||||||
return processStateProperty;
|
return processStateProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<? extends TradeState.LifeCycleState> lifeCycleStateProperty() {
|
public ReadOnlyObjectProperty<Trade.LifeCycleState> lifeCycleStateProperty() {
|
||||||
return lifeCycleStateProperty;
|
return lifeCycleStateProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,39 +22,37 @@ import io.bitsquare.btc.AddressEntry;
|
||||||
import io.bitsquare.btc.BlockChainService;
|
import io.bitsquare.btc.BlockChainService;
|
||||||
import io.bitsquare.btc.TradeWalletService;
|
import io.bitsquare.btc.TradeWalletService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
|
||||||
import io.bitsquare.common.handlers.FaultHandler;
|
import io.bitsquare.common.handlers.FaultHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.crypto.CryptoService;
|
import io.bitsquare.crypto.CryptoService;
|
||||||
import io.bitsquare.crypto.KeyRing;
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.crypto.MessageWithPubKey;
|
import io.bitsquare.crypto.MessageWithPubKey;
|
||||||
import io.bitsquare.crypto.SealedAndSignedMessage;
|
import io.bitsquare.crypto.SealedAndSignedMessage;
|
||||||
import io.bitsquare.fiat.FiatAccount;
|
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.offer.OfferBookService;
|
|
||||||
import io.bitsquare.p2p.AddressService;
|
import io.bitsquare.p2p.AddressService;
|
||||||
|
import io.bitsquare.p2p.DecryptedMessageHandler;
|
||||||
import io.bitsquare.p2p.MailboxMessage;
|
import io.bitsquare.p2p.MailboxMessage;
|
||||||
import io.bitsquare.p2p.MailboxService;
|
import io.bitsquare.p2p.MailboxService;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||||
import io.bitsquare.trade.handlers.TakeOfferResultHandler;
|
import io.bitsquare.trade.handlers.TakeOfferResultHandler;
|
||||||
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityProtocol;
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityModel;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityProtocol;
|
||||||
|
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
|
||||||
|
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
import io.bitsquare.trade.states.OffererTradeState;
|
import io.bitsquare.trade.states.OffererTradeState;
|
||||||
import io.bitsquare.trade.states.TakerTradeState;
|
|
||||||
import io.bitsquare.user.AccountSettings;
|
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
import org.bitcoinj.core.AddressFormatException;
|
import org.bitcoinj.core.AddressFormatException;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.InsufficientMoneyException;
|
import org.bitcoinj.core.InsufficientMoneyException;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.utils.Fiat;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
|
||||||
|
@ -77,12 +75,13 @@ import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
||||||
|
|
||||||
public class TradeManager {
|
public class TradeManager {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TradeManager.class);
|
private static final Logger log = LoggerFactory.getLogger(TradeManager.class);
|
||||||
|
|
||||||
private final User user;
|
private final User user;
|
||||||
private KeyRing keyRing;
|
private final KeyRing keyRing;
|
||||||
private final AccountSettings accountSettings;
|
|
||||||
private final MessageService messageService;
|
private final MessageService messageService;
|
||||||
private final MailboxService mailboxService;
|
private final MailboxService mailboxService;
|
||||||
private final AddressService addressService;
|
private final AddressService addressService;
|
||||||
|
@ -90,17 +89,13 @@ public class TradeManager {
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private final TradeWalletService tradeWalletService;
|
private final TradeWalletService tradeWalletService;
|
||||||
private final CryptoService<MailboxMessage> cryptoService;
|
private final CryptoService<MailboxMessage> cryptoService;
|
||||||
private final OfferBookService offerBookService;
|
private OpenOfferManager openOfferManager;
|
||||||
|
private ClosedTradableManager closedTradableManager;
|
||||||
private final ArbitrationRepository arbitrationRepository;
|
private final ArbitrationRepository arbitrationRepository;
|
||||||
|
|
||||||
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
|
private final Map<String, OfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
|
||||||
private final Storage<TradeList> pendingTradesStorage;
|
private final Storage<TradableList<Trade>> pendingTradesStorage;
|
||||||
private final Storage<TradeList> openOfferTradesStorage;
|
private final TradableList<Trade> pendingTrades;
|
||||||
private final TradeList<Trade> openOfferTrades;
|
|
||||||
private final TradeList<Trade> pendingTrades;
|
|
||||||
private final TradeList<Trade> closedTrades;
|
|
||||||
|
|
||||||
private boolean shutDownRequested;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -110,7 +105,6 @@ public class TradeManager {
|
||||||
@Inject
|
@Inject
|
||||||
public TradeManager(User user,
|
public TradeManager(User user,
|
||||||
KeyRing keyRing,
|
KeyRing keyRing,
|
||||||
AccountSettings accountSettings,
|
|
||||||
MessageService messageService,
|
MessageService messageService,
|
||||||
MailboxService mailboxService,
|
MailboxService mailboxService,
|
||||||
AddressService addressService,
|
AddressService addressService,
|
||||||
|
@ -118,12 +112,12 @@ public class TradeManager {
|
||||||
WalletService walletService,
|
WalletService walletService,
|
||||||
TradeWalletService tradeWalletService,
|
TradeWalletService tradeWalletService,
|
||||||
CryptoService<MailboxMessage> cryptoService,
|
CryptoService<MailboxMessage> cryptoService,
|
||||||
OfferBookService offerBookService,
|
OpenOfferManager openOfferManager,
|
||||||
|
ClosedTradableManager closedTradableManager,
|
||||||
ArbitrationRepository arbitrationRepository,
|
ArbitrationRepository arbitrationRepository,
|
||||||
@Named("storage.dir") File storageDir) {
|
@Named("storage.dir") File storageDir) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
this.accountSettings = accountSettings;
|
|
||||||
this.messageService = messageService;
|
this.messageService = messageService;
|
||||||
this.mailboxService = mailboxService;
|
this.mailboxService = mailboxService;
|
||||||
this.addressService = addressService;
|
this.addressService = addressService;
|
||||||
|
@ -131,20 +125,12 @@ public class TradeManager {
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.tradeWalletService = tradeWalletService;
|
this.tradeWalletService = tradeWalletService;
|
||||||
this.cryptoService = cryptoService;
|
this.cryptoService = cryptoService;
|
||||||
this.offerBookService = offerBookService;
|
this.openOfferManager = openOfferManager;
|
||||||
|
this.closedTradableManager = closedTradableManager;
|
||||||
this.arbitrationRepository = arbitrationRepository;
|
this.arbitrationRepository = arbitrationRepository;
|
||||||
|
|
||||||
openOfferTradesStorage = new Storage<>(storageDir);
|
|
||||||
pendingTradesStorage = new Storage<>(storageDir);
|
pendingTradesStorage = new Storage<>(storageDir);
|
||||||
|
this.pendingTrades = new TradableList<>(pendingTradesStorage, "PendingTrades");
|
||||||
this.openOfferTrades = new TradeList<>(openOfferTradesStorage, "OpenOfferTrades");
|
|
||||||
this.pendingTrades = new TradeList<>(pendingTradesStorage, "PendingTrades");
|
|
||||||
this.closedTrades = new TradeList<>(new Storage<>(storageDir), "ClosedTrades");
|
|
||||||
|
|
||||||
|
|
||||||
// In case the app did get killed the shutDown from the modules is not called, so we use a shutdown hook
|
|
||||||
Thread shutDownHookThread = new Thread(TradeManager.this::shutDown, "TradeManager.ShutDownHook");
|
|
||||||
Runtime.getRuntime().addShutdownHook(shutDownHookThread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,16 +142,6 @@ public class TradeManager {
|
||||||
// OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early.
|
// OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early.
|
||||||
public void onAllServicesInitialized() {
|
public void onAllServicesInitialized() {
|
||||||
log.trace("onAllServicesInitialized");
|
log.trace("onAllServicesInitialized");
|
||||||
for (Trade trade : openOfferTrades) {
|
|
||||||
Offer offer = trade.getOffer();
|
|
||||||
// We add own offers to offerbook when we go online again
|
|
||||||
offerBookService.addOffer(offer,
|
|
||||||
() -> log.debug("Successful removed open offer from DHT"),
|
|
||||||
(message, throwable) -> log.error("Remove open offer from DHT failed. " + message));
|
|
||||||
setupDepositPublishedListener(trade);
|
|
||||||
trade.setStorage(openOfferTradesStorage);
|
|
||||||
initTrade(trade);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are messages in our mailbox we apply it and remove them from the DHT
|
// If there are messages in our mailbox we apply it and remove them from the DHT
|
||||||
// We run that before initializing the pending trades to be sure the state is correct
|
// We run that before initializing the pending trades to be sure the state is correct
|
||||||
|
@ -173,10 +149,69 @@ public class TradeManager {
|
||||||
(encryptedMailboxMessages) -> {
|
(encryptedMailboxMessages) -> {
|
||||||
log.trace("mailboxService.getAllMessages success");
|
log.trace("mailboxService.getAllMessages success");
|
||||||
setMailboxMessagesToTrades(encryptedMailboxMessages);
|
setMailboxMessagesToTrades(encryptedMailboxMessages);
|
||||||
//TODO testing
|
emptyMailbox();
|
||||||
//emptyMailbox();
|
|
||||||
initPendingTrades();
|
initPendingTrades();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handler for incoming initial messages from taker
|
||||||
|
messageService.addDecryptedMessageHandler(new DecryptedMessageHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(MessageWithPubKey messageWithPubKey, Peer sender) {
|
||||||
|
// We get an encrypted message but don't do the signature check as we don't know the peer yet.
|
||||||
|
// A basic sig check is in done also at decryption time
|
||||||
|
Message message = messageWithPubKey.getMessage();
|
||||||
|
// Those 2 messages are initial request form the taker.
|
||||||
|
// RequestPayDepositMessage is used also in case of SellerAsTaker but there it is handled in the protocol as it is not an initial request
|
||||||
|
if (message instanceof RequestDepositTxInputsMessage ||
|
||||||
|
(message instanceof RequestPayDepositMessage && ((RequestPayDepositMessage) message).isInitialRequest))
|
||||||
|
handleInitialTakeOfferRequest((TradeMessage) message, sender);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleInitialTakeOfferRequest(TradeMessage message, Peer sender) {
|
||||||
|
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName() + " from " + sender);
|
||||||
|
try {
|
||||||
|
nonEmptyStringOf(message.tradeId);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.warn("Invalid requestDepositTxInputsMessage " + message.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<OpenOffer> openOfferOptional = openOfferManager.findOpenOffer(message.tradeId);
|
||||||
|
if (openOfferOptional.isPresent() && openOfferOptional.get().getState() == OpenOffer.State.AVAILABLE) {
|
||||||
|
Offer offer = openOfferOptional.get().getOffer();
|
||||||
|
openOfferManager.reserveOpenOffer(openOfferOptional.get());
|
||||||
|
|
||||||
|
OffererTrade trade;
|
||||||
|
if (offer.getDirection() == Offer.Direction.BUY)
|
||||||
|
trade = new BuyerAsOffererTrade(offer, pendingTradesStorage);
|
||||||
|
else
|
||||||
|
trade = new SellerAsOffererTrade(offer, pendingTradesStorage);
|
||||||
|
|
||||||
|
trade.setStorage(pendingTradesStorage);
|
||||||
|
pendingTrades.add(trade);
|
||||||
|
initTrade(trade);
|
||||||
|
trade.handleTakeOfferRequest(message, sender);
|
||||||
|
setupDepositPublishedListener(trade);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO respond
|
||||||
|
//(RequestDepositTxInputsMessage)message.
|
||||||
|
// messageService.sendEncryptedMessage(sender,messageWithPubKey.getMessage().);
|
||||||
|
log.info("We received a take offer request but don't have that offer anymore.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only after published we consider the openOffer as closed and the trade as completely initialized
|
||||||
|
private void setupDepositPublishedListener(Trade trade) {
|
||||||
|
trade.processStateProperty().addListener((ov, oldValue, newValue) -> {
|
||||||
|
log.debug("setupDepositPublishedListener state = " + newValue);
|
||||||
|
if (newValue == OffererTradeState.ProcessState.DEPOSIT_PUBLISHED) {
|
||||||
|
openOfferManager.closeOpenOffer(trade.getOffer());
|
||||||
|
trade.setTakeOfferDate(new Date());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMailboxMessagesToTrades(List<SealedAndSignedMessage> encryptedMessages) {
|
private void setMailboxMessagesToTrades(List<SealedAndSignedMessage> encryptedMessages) {
|
||||||
|
@ -208,20 +243,13 @@ public class TradeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initPendingTrades() {
|
private void initPendingTrades() {
|
||||||
log.trace("initPendingTrades");
|
|
||||||
List<Trade> failedTrades = new ArrayList<>();
|
List<Trade> failedTrades = new ArrayList<>();
|
||||||
for (Trade trade : pendingTrades) {
|
for (Trade trade : pendingTrades) {
|
||||||
// We continue an interrupted trade.
|
// We continue an interrupted trade.
|
||||||
// TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to
|
// TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to
|
||||||
// continue the trade, but that might fail.
|
// continue the trade, but that might fail.
|
||||||
|
|
||||||
boolean failed = false;
|
if (trade.lifeCycleState == Trade.LifeCycleState.FAILED) {
|
||||||
if (trade instanceof TakerTrade)
|
|
||||||
failed = trade.lifeCycleState == TakerTradeState.LifeCycleState.FAILED;
|
|
||||||
else if (trade instanceof OffererTrade)
|
|
||||||
failed = trade.lifeCycleState == OffererTradeState.LifeCycleState.FAILED;
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
failedTrades.add(trade);
|
failedTrades.add(trade);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -232,63 +260,21 @@ public class TradeManager {
|
||||||
}
|
}
|
||||||
for (Trade trade : failedTrades) {
|
for (Trade trade : failedTrades) {
|
||||||
pendingTrades.remove(trade);
|
pendingTrades.remove(trade);
|
||||||
closedTrades.add(trade);
|
closedTradableManager.add(trade);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutDown() {
|
|
||||||
if (!shutDownRequested) {
|
|
||||||
log.debug("shutDown");
|
|
||||||
shutDownRequested = true;
|
|
||||||
// we remove own offers form offerbook when we go offline
|
|
||||||
for (Trade trade : openOfferTrades) {
|
|
||||||
Offer offer = trade.getOffer();
|
|
||||||
offerBookService.removeOfferAtShutDown(offer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Offer
|
// Called from Offerbook when offer gets removed from DHT
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void placeOffer(String id,
|
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
|
||||||
Offer.Direction direction,
|
disposeCheckOfferAvailabilityRequest(offer);
|
||||||
Fiat price,
|
|
||||||
Coin amount,
|
|
||||||
Coin minAmount,
|
|
||||||
TransactionResultHandler resultHandler,
|
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
|
||||||
|
|
||||||
FiatAccount fiatAccount = user.currentFiatAccountProperty().get();
|
|
||||||
Offer offer = new Offer(id,
|
|
||||||
keyRing.getPubKeyRing(),
|
|
||||||
direction,
|
|
||||||
price.getValue(),
|
|
||||||
amount,
|
|
||||||
minAmount,
|
|
||||||
fiatAccount.type,
|
|
||||||
fiatAccount.currencyCode,
|
|
||||||
fiatAccount.country,
|
|
||||||
fiatAccount.id,
|
|
||||||
accountSettings.getAcceptedArbitratorIds(),
|
|
||||||
accountSettings.getSecurityDeposit(),
|
|
||||||
accountSettings.getAcceptedCountries(),
|
|
||||||
accountSettings.getAcceptedLanguageLocaleCodes());
|
|
||||||
|
|
||||||
PlaceOfferModel model = new PlaceOfferModel(offer, walletService, tradeWalletService, offerBookService);
|
|
||||||
|
|
||||||
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
|
||||||
model,
|
|
||||||
transaction -> handlePlaceOfferResult(transaction, offer, resultHandler),
|
|
||||||
errorMessageHandler::handleErrorMessage
|
|
||||||
);
|
|
||||||
|
|
||||||
placeOfferProtocol.placeOffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePlaceOfferResult(Transaction transaction, Offer offer, TransactionResultHandler resultHandler) {
|
|
||||||
|
/* private void handlePlaceOfferResult(Transaction transaction, Offer offer, TransactionResultHandler resultHandler) {
|
||||||
Trade trade;
|
Trade trade;
|
||||||
if (offer.getDirection() == Offer.Direction.BUY)
|
if (offer.getDirection() == Offer.Direction.BUY)
|
||||||
trade = new BuyerAsOffererTrade(offer, openOfferTradesStorage);
|
trade = new BuyerAsOffererTrade(offer, openOfferTradesStorage);
|
||||||
|
@ -299,9 +285,9 @@ public class TradeManager {
|
||||||
initTrade(trade);
|
initTrade(trade);
|
||||||
setupDepositPublishedListener(trade);
|
setupDepositPublishedListener(trade);
|
||||||
resultHandler.handleResult(transaction);
|
resultHandler.handleResult(transaction);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private void setupDepositPublishedListener(Trade trade) {
|
/* private void setupDepositPublishedListener(Trade trade) {
|
||||||
trade.processStateProperty().addListener((ov, oldValue, newValue) -> {
|
trade.processStateProperty().addListener((ov, oldValue, newValue) -> {
|
||||||
log.debug("setupDepositPublishedListener state = " + newValue);
|
log.debug("setupDepositPublishedListener state = " + newValue);
|
||||||
if (newValue == OffererTradeState.ProcessState.DEPOSIT_PUBLISHED) {
|
if (newValue == OffererTradeState.ProcessState.DEPOSIT_PUBLISHED) {
|
||||||
|
@ -314,13 +300,13 @@ public class TradeManager {
|
||||||
trade.setStorage(pendingTradesStorage);
|
trade.setStorage(pendingTradesStorage);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public void onCancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
/* public void onCancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
|
removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
private void removeOpenOffer(Offer offer,
|
/* private void removeOpenOffer(Offer offer,
|
||||||
ResultHandler resultHandler,
|
ResultHandler resultHandler,
|
||||||
ErrorMessageHandler errorMessageHandler,
|
ErrorMessageHandler errorMessageHandler,
|
||||||
boolean isCancelRequest) {
|
boolean isCancelRequest) {
|
||||||
|
@ -345,7 +331,7 @@ public class TradeManager {
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
},
|
},
|
||||||
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
|
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -354,13 +340,13 @@ public class TradeManager {
|
||||||
|
|
||||||
public void checkOfferAvailability(Offer offer) {
|
public void checkOfferAvailability(Offer offer) {
|
||||||
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
||||||
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(
|
OfferAvailabilityModel model = new OfferAvailabilityModel(
|
||||||
offer,
|
offer,
|
||||||
keyRing.getPubKeyRing(),
|
keyRing.getPubKeyRing(),
|
||||||
messageService,
|
messageService,
|
||||||
addressService);
|
addressService);
|
||||||
|
|
||||||
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
|
OfferAvailabilityProtocol protocol = new OfferAvailabilityProtocol(model,
|
||||||
() -> disposeCheckOfferAvailabilityRequest(offer),
|
() -> disposeCheckOfferAvailabilityRequest(offer),
|
||||||
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
|
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
|
||||||
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
|
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
|
||||||
|
@ -378,15 +364,15 @@ public class TradeManager {
|
||||||
|
|
||||||
// First we check if offer is still available then we create the trade with the protocol
|
// First we check if offer is still available then we create the trade with the protocol
|
||||||
public void requestTakeOffer(Coin amount, Offer offer, TakeOfferResultHandler takeOfferResultHandler) {
|
public void requestTakeOffer(Coin amount, Offer offer, TakeOfferResultHandler takeOfferResultHandler) {
|
||||||
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, keyRing.getPubKeyRing(), messageService, addressService);
|
OfferAvailabilityModel model = new OfferAvailabilityModel(offer, keyRing.getPubKeyRing(), messageService, addressService);
|
||||||
CheckOfferAvailabilityProtocol availabilityProtocol = new CheckOfferAvailabilityProtocol(model,
|
OfferAvailabilityProtocol availabilityProtocol = new OfferAvailabilityProtocol(model,
|
||||||
() -> createTrade(amount, offer, model, takeOfferResultHandler),
|
() -> createTrade(amount, offer, model, takeOfferResultHandler),
|
||||||
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
|
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
|
||||||
checkOfferAvailabilityProtocolMap.put(offer.getId(), availabilityProtocol);
|
checkOfferAvailabilityProtocolMap.put(offer.getId(), availabilityProtocol);
|
||||||
availabilityProtocol.checkOfferAvailability();
|
availabilityProtocol.checkOfferAvailability();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTrade(Coin amount, Offer offer, CheckOfferAvailabilityModel model, TakeOfferResultHandler
|
private void createTrade(Coin amount, Offer offer, OfferAvailabilityModel model, TakeOfferResultHandler
|
||||||
takeOfferResultHandler) {
|
takeOfferResultHandler) {
|
||||||
disposeCheckOfferAvailabilityRequest(offer);
|
disposeCheckOfferAvailabilityRequest(offer);
|
||||||
if (offer.getState() == Offer.State.AVAILABLE) {
|
if (offer.getState() == Offer.State.AVAILABLE) {
|
||||||
|
@ -419,13 +405,10 @@ public class TradeManager {
|
||||||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||||
if (transaction != null) {
|
if (transaction != null) {
|
||||||
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
|
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
|
||||||
if (trade instanceof OffererTrade)
|
trade.setLifeCycleState(Trade.LifeCycleState.COMPLETED);
|
||||||
trade.setLifeCycleState(OffererTradeState.LifeCycleState.COMPLETED);
|
|
||||||
else if (trade instanceof TakerTrade)
|
|
||||||
trade.setLifeCycleState(TakerTradeState.LifeCycleState.COMPLETED);
|
|
||||||
|
|
||||||
pendingTrades.remove(trade);
|
pendingTrades.remove(trade);
|
||||||
closedTrades.add(trade);
|
closedTradableManager.add(trade);
|
||||||
|
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
}
|
}
|
||||||
|
@ -452,27 +435,27 @@ public class TradeManager {
|
||||||
// Called from Offerbook when offer gets removed from DHT
|
// Called from Offerbook when offer gets removed from DHT
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
|
/* public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
|
||||||
disposeCheckOfferAvailabilityRequest(offer);
|
disposeCheckOfferAvailabilityRequest(offer);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getters
|
// Getters
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public ObservableList<Trade> getOpenOfferTrades() {
|
/* public ObservableList<Trade> getOpenOfferTrades() {
|
||||||
return openOfferTrades.getObservableList();
|
return openOfferTrades.getObservableList();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public ObservableList<Trade> getPendingTrades() {
|
public ObservableList<Trade> getPendingTrades() {
|
||||||
return pendingTrades.getObservableList();
|
return pendingTrades.getObservableList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableList<Trade> getClosedTrades() {
|
/* public ObservableList<Trade> getClosedTrades() {
|
||||||
return closedTrades.getObservableList();
|
return closedTrades.getObservableList();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Misc
|
// Misc
|
||||||
|
@ -480,7 +463,7 @@ public class TradeManager {
|
||||||
|
|
||||||
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
|
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
|
||||||
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
||||||
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
|
OfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
|
||||||
protocol.cancel();
|
protocol.cancel();
|
||||||
checkOfferAvailabilityProtocolMap.remove(offer.getId());
|
checkOfferAvailabilityProtocolMap.remove(offer.getId());
|
||||||
}
|
}
|
||||||
|
@ -499,6 +482,6 @@ public class TradeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMyOffer(Offer offer) {
|
public boolean isMyOffer(Offer offer) {
|
||||||
return offer.getPubKeyRing().getHashString().equals(keyRing.getPubKeyRing().getHashString());
|
return offer.isMyOffer(keyRing);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,8 +18,8 @@
|
||||||
package io.bitsquare.trade;
|
package io.bitsquare.trade;
|
||||||
|
|
||||||
import io.bitsquare.BitsquareModule;
|
import io.bitsquare.BitsquareModule;
|
||||||
|
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||||
|
|
||||||
import com.google.inject.Injector;
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -37,11 +37,12 @@ public class TradeModule extends BitsquareModule {
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(TradeManager.class).in(Singleton.class);
|
bind(TradeManager.class).in(Singleton.class);
|
||||||
|
bind(ClosedTradableManager.class).in(Singleton.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/* @Override
|
||||||
protected void doClose(Injector injector) {
|
protected void doClose(Injector injector) {
|
||||||
log.trace("doClose " + getClass().getSimpleName());
|
log.trace("doClose " + getClass().getSimpleName());
|
||||||
injector.getInstance(TradeManager.class).shutDown();
|
injector.getInstance(TradeManager.class).shutDown();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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.closed;
|
||||||
|
|
||||||
|
import io.bitsquare.crypto.KeyRing;
|
||||||
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.Tradable;
|
||||||
|
import io.bitsquare.trade.TradableList;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class ClosedTradableManager {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ClosedTradableManager.class);
|
||||||
|
private final TradableList<Tradable> closedTrades;
|
||||||
|
private KeyRing keyRing;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ClosedTradableManager(KeyRing keyRing, @Named("storage.dir") File storageDir) {
|
||||||
|
this.keyRing = keyRing;
|
||||||
|
this.closedTrades = new TradableList<>(new Storage<>(storageDir), "ClosedTrades");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Tradable tradable) {
|
||||||
|
closedTrades.add(tradable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasMyOffer(Offer offer) {
|
||||||
|
return offer.isMyOffer(keyRing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableList<Tradable> getClosedTrades() {
|
||||||
|
return closedTrades.getObservableList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -15,9 +15,10 @@
|
||||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.bitsquare.offer;
|
package io.bitsquare.trade.offer;
|
||||||
|
|
||||||
import io.bitsquare.btc.Restrictions;
|
import io.bitsquare.btc.Restrictions;
|
||||||
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.crypto.PubKeyRing;
|
import io.bitsquare.crypto.PubKeyRing;
|
||||||
import io.bitsquare.fiat.FiatAccount;
|
import io.bitsquare.fiat.FiatAccount;
|
||||||
import io.bitsquare.locale.Country;
|
import io.bitsquare.locale.Country;
|
||||||
|
@ -51,12 +52,11 @@ public class Offer implements Serializable {
|
||||||
public enum Direction {BUY, SELL}
|
public enum Direction {BUY, SELL}
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
UNKNOWN,
|
UNDEFINED,
|
||||||
AVAILABLE,
|
AVAILABLE,
|
||||||
RESERVED,
|
NOT_AVAILABLE,
|
||||||
REMOVED,
|
REMOVED,
|
||||||
OFFERER_OFFLINE,
|
OFFERER_OFFLINE
|
||||||
FAULT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ public class Offer implements Serializable {
|
||||||
|
|
||||||
// Mutable property. Has to be set before offer is save in DHT as it changes the objects hash!
|
// Mutable property. Has to be set before offer is save in DHT as it changes the objects hash!
|
||||||
private String offerFeePaymentTxID;
|
private String offerFeePaymentTxID;
|
||||||
private State state = State.UNKNOWN;
|
private State state = State.UNDEFINED;
|
||||||
|
|
||||||
// Those state properties are transient and only used at runtime!
|
// Those state properties are transient and only used at runtime!
|
||||||
// don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated
|
// don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated
|
||||||
|
@ -125,7 +125,7 @@ public class Offer implements Serializable {
|
||||||
this.acceptedLanguageCodes = acceptedLanguageCodes;
|
this.acceptedLanguageCodes = acceptedLanguageCodes;
|
||||||
|
|
||||||
creationDate = new Date();
|
creationDate = new Date();
|
||||||
setState(State.UNKNOWN);
|
setState(State.UNDEFINED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
@ -160,6 +160,10 @@ public class Offer implements Serializable {
|
||||||
// TODO check upper and lower bounds for fiat
|
// TODO check upper and lower bounds for fiat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMyOffer(KeyRing keyRing) {
|
||||||
|
return getPubKeyRing().getHashString().equals(keyRing.getPubKeyRing().getHashString());
|
||||||
|
}
|
||||||
|
|
||||||
public Fiat getVolumeByAmount(Coin amount) {
|
public Fiat getVolumeByAmount(Coin amount) {
|
||||||
if (fiatPrice != 0 && amount != null && !amount.isZero())
|
if (fiatPrice != 0 && amount != null && !amount.isZero())
|
||||||
return new ExchangeRate(Fiat.valueOf(currencyCode, fiatPrice)).coinToFiat(amount);
|
return new ExchangeRate(Fiat.valueOf(currencyCode, fiatPrice)).coinToFiat(amount);
|
|
@ -15,7 +15,7 @@
|
||||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.bitsquare.offer;
|
package io.bitsquare.trade.offer;
|
||||||
|
|
||||||
import io.bitsquare.common.handlers.FaultHandler;
|
import io.bitsquare.common.handlers.FaultHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
|
@ -15,13 +15,20 @@
|
||||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.bitsquare.offer;
|
package io.bitsquare.trade.offer;
|
||||||
|
|
||||||
import io.bitsquare.BitsquareModule;
|
import io.bitsquare.BitsquareModule;
|
||||||
|
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
public abstract class OfferModule extends BitsquareModule {
|
public abstract class OfferModule extends BitsquareModule {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(OfferModule.class);
|
||||||
|
|
||||||
protected OfferModule(Environment env) {
|
protected OfferModule(Environment env) {
|
||||||
super(env);
|
super(env);
|
||||||
|
@ -29,9 +36,16 @@ public abstract class OfferModule extends BitsquareModule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void configure() {
|
protected final void configure() {
|
||||||
|
bind(OpenOfferManager.class).in(Singleton.class);
|
||||||
doConfigure();
|
doConfigure();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doConfigure() {
|
protected void doConfigure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doClose(Injector injector) {
|
||||||
|
log.trace("doClose " + getClass().getSimpleName());
|
||||||
|
injector.getInstance(OpenOfferManager.class).shutDown();
|
||||||
|
}
|
||||||
}
|
}
|
124
core/src/main/java/io/bitsquare/trade/offer/OpenOffer.java
Normal file
124
core/src/main/java/io/bitsquare/trade/offer/OpenOffer.java
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* 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.offer;
|
||||||
|
|
||||||
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.Tradable;
|
||||||
|
import io.bitsquare.trade.TradableList;
|
||||||
|
|
||||||
|
import org.bitcoinj.utils.Threading;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class OpenOffer implements Tradable, Serializable {
|
||||||
|
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(OpenOffer.class);
|
||||||
|
|
||||||
|
transient private static final long TIMEOUT = 5000;
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
AVAILABLE,
|
||||||
|
RESERVED,
|
||||||
|
CLOSED,
|
||||||
|
CANCELED
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Offer offer;
|
||||||
|
private State state = State.AVAILABLE;
|
||||||
|
|
||||||
|
transient private Timer timeoutTimer;
|
||||||
|
transient private Storage<TradableList<OpenOffer>> storage;
|
||||||
|
|
||||||
|
public OpenOffer(Offer offer, Storage<TradableList<OpenOffer>> storage) {
|
||||||
|
this.offer = offer;
|
||||||
|
this.storage = storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDate() {
|
||||||
|
return offer.getCreationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return offer.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Offer getOffer() {
|
||||||
|
return offer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStorage(Storage<TradableList<OpenOffer>> storage) {
|
||||||
|
this.storage = storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(State state) {
|
||||||
|
log.trace("setState" + state);
|
||||||
|
this.state = state;
|
||||||
|
storage.queueUpForSave();
|
||||||
|
|
||||||
|
// We keep it reserved for a limited time, if trade preparation fails we revert to available state
|
||||||
|
if (this.state == State.RESERVED)
|
||||||
|
startTimeout();
|
||||||
|
else
|
||||||
|
stopTimeout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void startTimeout() {
|
||||||
|
log.trace("startTimeout");
|
||||||
|
stopTimeout();
|
||||||
|
|
||||||
|
timeoutTimer = new Timer();
|
||||||
|
TimerTask task = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Threading.USER_THREAD.execute(() -> {
|
||||||
|
log.debug("Timeout reached");
|
||||||
|
if (state == State.RESERVED)
|
||||||
|
setState(State.AVAILABLE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
timeoutTimer.schedule(task, TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void stopTimeout() {
|
||||||
|
log.trace("stopTimeout");
|
||||||
|
if (timeoutTimer != null) {
|
||||||
|
timeoutTimer.cancel();
|
||||||
|
timeoutTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,287 @@
|
||||||
|
/*
|
||||||
|
* 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.offer;
|
||||||
|
|
||||||
|
import io.bitsquare.btc.TradeWalletService;
|
||||||
|
import io.bitsquare.btc.WalletService;
|
||||||
|
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||||
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
|
import io.bitsquare.crypto.KeyRing;
|
||||||
|
import io.bitsquare.crypto.MessageWithPubKey;
|
||||||
|
import io.bitsquare.fiat.FiatAccount;
|
||||||
|
import io.bitsquare.p2p.DecryptedMessageHandler;
|
||||||
|
import io.bitsquare.p2p.Message;
|
||||||
|
import io.bitsquare.p2p.MessageService;
|
||||||
|
import io.bitsquare.p2p.Peer;
|
||||||
|
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||||
|
import io.bitsquare.storage.Storage;
|
||||||
|
import io.bitsquare.trade.TradableList;
|
||||||
|
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||||
|
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.availability.messages.OfferAvailabilityRequest;
|
||||||
|
import io.bitsquare.trade.protocol.availability.messages.OfferAvailabilityResponse;
|
||||||
|
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
||||||
|
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
||||||
|
import io.bitsquare.user.AccountSettings;
|
||||||
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.utils.Fiat;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static com.google.inject.internal.util.$Preconditions.checkNotNull;
|
||||||
|
import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
||||||
|
|
||||||
|
public class OpenOfferManager {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(OpenOfferManager.class);
|
||||||
|
|
||||||
|
private final User user;
|
||||||
|
private final KeyRing keyRing;
|
||||||
|
private final AccountSettings accountSettings;
|
||||||
|
private final WalletService walletService;
|
||||||
|
private MessageService messageService;
|
||||||
|
private final TradeWalletService tradeWalletService;
|
||||||
|
private final OfferBookService offerBookService;
|
||||||
|
private ClosedTradableManager closedTradableManager;
|
||||||
|
|
||||||
|
private final TradableList<OpenOffer> openOffers;
|
||||||
|
private final Storage<TradableList<OpenOffer>> openOffersStorage;
|
||||||
|
private boolean shutDownRequested;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public OpenOfferManager(User user,
|
||||||
|
KeyRing keyRing,
|
||||||
|
AccountSettings accountSettings,
|
||||||
|
WalletService walletService,
|
||||||
|
MessageService messageService,
|
||||||
|
TradeWalletService tradeWalletService,
|
||||||
|
OfferBookService offerBookService,
|
||||||
|
ClosedTradableManager closedTradableManager,
|
||||||
|
@Named("storage.dir") File storageDir) {
|
||||||
|
this.user = user;
|
||||||
|
this.keyRing = keyRing;
|
||||||
|
this.accountSettings = accountSettings;
|
||||||
|
this.walletService = walletService;
|
||||||
|
this.messageService = messageService;
|
||||||
|
this.tradeWalletService = tradeWalletService;
|
||||||
|
this.offerBookService = offerBookService;
|
||||||
|
this.closedTradableManager = closedTradableManager;
|
||||||
|
|
||||||
|
openOffersStorage = new Storage<>(storageDir);
|
||||||
|
this.openOffers = new TradableList<>(openOffersStorage, "OpenOffers");
|
||||||
|
|
||||||
|
// In case the app did get killed the shutDown from the modules is not called, so we use a shutdown hook
|
||||||
|
Thread shutDownHookThread = new Thread(OpenOfferManager.this::shutDown, "OpenOfferManager.ShutDownHook");
|
||||||
|
Runtime.getRuntime().addShutdownHook(shutDownHookThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lifecycle
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onAllServicesInitialized() {
|
||||||
|
log.trace("onAllServicesInitialized");
|
||||||
|
|
||||||
|
// Handler for incoming offer availability requests
|
||||||
|
messageService.addDecryptedMessageHandler(new DecryptedMessageHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(MessageWithPubKey messageWithPubKey, Peer sender) {
|
||||||
|
// We get an encrypted message but don't do the signature check as we don't know the peer yet.
|
||||||
|
// A basic sig check is in done also at decryption time
|
||||||
|
Message message = messageWithPubKey.getMessage();
|
||||||
|
if (message instanceof OfferAvailabilityRequest)
|
||||||
|
handleOfferAvailabilityRequest((OfferAvailabilityRequest) message, sender);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (OpenOffer openOffer : openOffers) {
|
||||||
|
// We add own offers to offerbook when we go online again
|
||||||
|
offerBookService.addOffer(openOffer.getOffer(),
|
||||||
|
() -> log.debug("Successful added offer to DHT"),
|
||||||
|
(message, throwable) -> log.error("Add offer to DHT failed. " + message));
|
||||||
|
//setupDepositPublishedListener(openOffer);
|
||||||
|
openOffer.setStorage(openOffersStorage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutDown() {
|
||||||
|
if (!shutDownRequested) {
|
||||||
|
log.debug("shutDown");
|
||||||
|
shutDownRequested = true;
|
||||||
|
// we remove own offers form offerbook when we go offline
|
||||||
|
for (OpenOffer openOffer : openOffers) {
|
||||||
|
offerBookService.removeOfferAtShutDown(openOffer.getOffer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// API
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onPlaceOffer(String id,
|
||||||
|
Offer.Direction direction,
|
||||||
|
Fiat price,
|
||||||
|
Coin amount,
|
||||||
|
Coin minAmount,
|
||||||
|
TransactionResultHandler resultHandler,
|
||||||
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
|
|
||||||
|
FiatAccount fiatAccount = user.currentFiatAccountProperty().get();
|
||||||
|
Offer offer = new Offer(id,
|
||||||
|
keyRing.getPubKeyRing(),
|
||||||
|
direction,
|
||||||
|
price.getValue(),
|
||||||
|
amount,
|
||||||
|
minAmount,
|
||||||
|
fiatAccount.type,
|
||||||
|
fiatAccount.currencyCode,
|
||||||
|
fiatAccount.country,
|
||||||
|
fiatAccount.id,
|
||||||
|
accountSettings.getAcceptedArbitratorIds(),
|
||||||
|
accountSettings.getSecurityDeposit(),
|
||||||
|
accountSettings.getAcceptedCountries(),
|
||||||
|
accountSettings.getAcceptedLanguageLocaleCodes());
|
||||||
|
|
||||||
|
PlaceOfferModel model = new PlaceOfferModel(offer, walletService, tradeWalletService, offerBookService);
|
||||||
|
|
||||||
|
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
||||||
|
model,
|
||||||
|
transaction -> {
|
||||||
|
OpenOffer openOffer = new OpenOffer(offer, openOffersStorage);
|
||||||
|
openOffers.add(openOffer);
|
||||||
|
openOffersStorage.queueUpForSave();
|
||||||
|
resultHandler.handleResult(transaction);
|
||||||
|
},
|
||||||
|
errorMessageHandler::handleErrorMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
placeOfferProtocol.placeOffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void onCancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
|
Optional<OpenOffer> openOfferOptional = findOpenOffer(offer.getId());
|
||||||
|
if (openOfferOptional.isPresent())
|
||||||
|
onCancelOpenOffer(openOfferOptional.get(), resultHandler, errorMessageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCancelOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
|
offerBookService.removeOffer(openOffer.getOffer(),
|
||||||
|
() -> {
|
||||||
|
openOffer.getOffer().setState(Offer.State.REMOVED);
|
||||||
|
openOffer.setState(OpenOffer.State.CANCELED);
|
||||||
|
openOffers.remove(openOffer);
|
||||||
|
closedTradableManager.add(openOffer);
|
||||||
|
//disposeCheckOfferAvailabilityRequest(offer);
|
||||||
|
resultHandler.handleResult();
|
||||||
|
},
|
||||||
|
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reserveOpenOffer(OpenOffer openOffer) {
|
||||||
|
openOffer.setState(OpenOffer.State.RESERVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Getters
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public boolean isMyOffer(Offer offer) {
|
||||||
|
return offer.isMyOffer(keyRing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableList<OpenOffer> getOpenOffers() {
|
||||||
|
return openOffers.getObservableList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<OpenOffer> findOpenOffer(String offerId) {
|
||||||
|
return openOffers.stream().filter(openOffer -> openOffer.getOffer().getId().equals(offerId)).findAny();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close openOffer after deposit published
|
||||||
|
public void closeOpenOffer(Offer offer) {
|
||||||
|
findOpenOffer(offer.getId()).ifPresent(openOffer -> {
|
||||||
|
openOffers.remove(openOffer);
|
||||||
|
openOffer.setState(OpenOffer.State.CLOSED);
|
||||||
|
offerBookService.removeOffer(openOffer.getOffer(),
|
||||||
|
() -> log.trace("Successful removed offer"),
|
||||||
|
(message, throwable) -> log.error(message));
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Offer Availability
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void handleOfferAvailabilityRequest(OfferAvailabilityRequest message, Peer sender) {
|
||||||
|
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName() + " from " + sender);
|
||||||
|
try {
|
||||||
|
nonEmptyStringOf(message.offerId);
|
||||||
|
checkNotNull(message.getPubKeyRing());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.warn("Invalid message " + message.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<OpenOffer> openOfferOptional = findOpenOffer(message.offerId);
|
||||||
|
boolean isAvailable = openOfferOptional.isPresent() && openOfferOptional.get().getState() == OpenOffer.State.AVAILABLE;
|
||||||
|
try {
|
||||||
|
OfferAvailabilityResponse offerAvailabilityResponse = new OfferAvailabilityResponse(message.offerId, isAvailable);
|
||||||
|
messageService.sendEncryptedMessage(sender,
|
||||||
|
message.getPubKeyRing(),
|
||||||
|
offerAvailabilityResponse,
|
||||||
|
new SendMessageListener() {
|
||||||
|
@Override
|
||||||
|
public void handleResult() {
|
||||||
|
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleFault() {
|
||||||
|
log.info("Sending ReportOfferAvailabilityMessage failed.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
log.info("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,15 +15,15 @@
|
||||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.bitsquare.offer.tomp2p;
|
package io.bitsquare.trade.offer.tomp2p;
|
||||||
|
|
||||||
import io.bitsquare.common.handlers.FaultHandler;
|
import io.bitsquare.common.handlers.FaultHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.crypto.KeyRing;
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.offer.OfferBookService;
|
|
||||||
import io.bitsquare.p2p.tomp2p.TomP2PDHTService;
|
import io.bitsquare.p2p.tomp2p.TomP2PDHTService;
|
||||||
import io.bitsquare.p2p.tomp2p.TomP2PNode;
|
import io.bitsquare.p2p.tomp2p.TomP2PNode;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
import io.bitsquare.trade.offer.OfferBookService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.bitsquare.offer.tomp2p;
|
package io.bitsquare.trade.offer.tomp2p;
|
||||||
|
|
||||||
import io.bitsquare.offer.OfferBookService;
|
import io.bitsquare.trade.offer.OfferBookService;
|
||||||
import io.bitsquare.offer.OfferModule;
|
import io.bitsquare.trade.offer.OfferModule;
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
|
@ -19,17 +19,17 @@ package io.bitsquare.trade.protocol.availability;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.Model;
|
import io.bitsquare.common.taskrunner.Model;
|
||||||
import io.bitsquare.crypto.PubKeyRing;
|
import io.bitsquare.crypto.PubKeyRing;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.AddressService;
|
import io.bitsquare.p2p.AddressService;
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.OfferMessage;
|
import io.bitsquare.trade.protocol.availability.messages.OfferMessage;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class CheckOfferAvailabilityModel implements Model {
|
public class OfferAvailabilityModel implements Model {
|
||||||
private static final Logger log = LoggerFactory.getLogger(CheckOfferAvailabilityModel.class);
|
private static final Logger log = LoggerFactory.getLogger(OfferAvailabilityModel.class);
|
||||||
|
|
||||||
public final Offer offer;
|
public final Offer offer;
|
||||||
private final PubKeyRing pubKeyRing;
|
private final PubKeyRing pubKeyRing;
|
||||||
|
@ -39,7 +39,7 @@ public class CheckOfferAvailabilityModel implements Model {
|
||||||
private Peer peer;
|
private Peer peer;
|
||||||
private OfferMessage message;
|
private OfferMessage message;
|
||||||
|
|
||||||
public CheckOfferAvailabilityModel(Offer offer, PubKeyRing pubKeyRing, MessageService messageService, AddressService addressService) {
|
public OfferAvailabilityModel(Offer offer, PubKeyRing pubKeyRing, MessageService messageService, AddressService addressService) {
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.pubKeyRing = pubKeyRing;
|
this.pubKeyRing = pubKeyRing;
|
||||||
this.messageService = messageService;
|
this.messageService = messageService;
|
||||||
|
@ -64,12 +64,10 @@ public class CheckOfferAvailabilityModel implements Model {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void persist() {
|
public void persist() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete() {
|
public void onComplete() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PubKeyRing getPubKeyRing() {
|
public PubKeyRing getPubKeyRing() {
|
|
@ -21,15 +21,15 @@ import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
import io.bitsquare.crypto.MessageWithPubKey;
|
import io.bitsquare.crypto.MessageWithPubKey;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.DecryptedMessageHandler;
|
import io.bitsquare.p2p.DecryptedMessageHandler;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
import io.bitsquare.trade.protocol.availability.messages.OfferAvailabilityResponse;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.OfferMessage;
|
import io.bitsquare.trade.protocol.availability.messages.OfferMessage;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
|
||||||
import io.bitsquare.trade.protocol.availability.tasks.GetPeerAddress;
|
import io.bitsquare.trade.protocol.availability.tasks.GetPeerAddress;
|
||||||
import io.bitsquare.trade.protocol.availability.tasks.ProcessReportOfferAvailabilityMessage;
|
import io.bitsquare.trade.protocol.availability.tasks.ProcessOfferAvailabilityResponse;
|
||||||
import io.bitsquare.trade.protocol.availability.tasks.SendRequestIsOfferAvailableMessage;
|
import io.bitsquare.trade.protocol.availability.tasks.SendOfferAvailabilityRequest;
|
||||||
|
|
||||||
import org.bitcoinj.utils.Threading;
|
import org.bitcoinj.utils.Threading;
|
||||||
|
|
||||||
|
@ -41,26 +41,26 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
||||||
|
|
||||||
public class CheckOfferAvailabilityProtocol {
|
public class OfferAvailabilityProtocol {
|
||||||
private static final Logger log = LoggerFactory.getLogger(CheckOfferAvailabilityProtocol.class);
|
private static final Logger log = LoggerFactory.getLogger(OfferAvailabilityProtocol.class);
|
||||||
|
|
||||||
private static final long TIMEOUT = 10000;
|
private static final long TIMEOUT = 10000;
|
||||||
|
|
||||||
private final CheckOfferAvailabilityModel model;
|
private final OfferAvailabilityModel model;
|
||||||
private final ResultHandler resultHandler;
|
private final ResultHandler resultHandler;
|
||||||
private final ErrorMessageHandler errorMessageHandler;
|
private final ErrorMessageHandler errorMessageHandler;
|
||||||
private final DecryptedMessageHandler decryptedMessageHandler;
|
private final DecryptedMessageHandler decryptedMessageHandler;
|
||||||
private Timer timeoutTimer;
|
private Timer timeoutTimer;
|
||||||
|
|
||||||
private boolean isCanceled;
|
private boolean isCanceled;
|
||||||
private TaskRunner<CheckOfferAvailabilityModel> taskRunner;
|
private TaskRunner<OfferAvailabilityModel> taskRunner;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public CheckOfferAvailabilityProtocol(CheckOfferAvailabilityModel model, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
public OfferAvailabilityProtocol(OfferAvailabilityModel model, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.resultHandler = resultHandler;
|
this.resultHandler = resultHandler;
|
||||||
this.errorMessageHandler = errorMessageHandler;
|
this.errorMessageHandler = errorMessageHandler;
|
||||||
|
@ -79,7 +79,7 @@ public class CheckOfferAvailabilityProtocol {
|
||||||
|
|
||||||
public void checkOfferAvailability() {
|
public void checkOfferAvailability() {
|
||||||
// reset
|
// reset
|
||||||
model.offer.setState(Offer.State.UNKNOWN);
|
model.offer.setState(Offer.State.UNDEFINED);
|
||||||
|
|
||||||
model.messageService.addDecryptedMessageHandler(decryptedMessageHandler);
|
model.messageService.addDecryptedMessageHandler(decryptedMessageHandler);
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ public class CheckOfferAvailabilityProtocol {
|
||||||
);
|
);
|
||||||
taskRunner.addTasks(
|
taskRunner.addTasks(
|
||||||
GetPeerAddress.class,
|
GetPeerAddress.class,
|
||||||
SendRequestIsOfferAvailableMessage.class
|
SendOfferAvailabilityRequest.class
|
||||||
);
|
);
|
||||||
startTimeout();
|
startTimeout();
|
||||||
taskRunner.run();
|
taskRunner.run();
|
||||||
|
@ -111,13 +111,13 @@ public class CheckOfferAvailabilityProtocol {
|
||||||
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName() + " from " + sender);
|
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName() + " from " + sender);
|
||||||
if (message instanceof OfferMessage) {
|
if (message instanceof OfferMessage) {
|
||||||
nonEmptyStringOf(((OfferMessage) message).offerId);
|
nonEmptyStringOf(((OfferMessage) message).offerId);
|
||||||
if (message instanceof ReportOfferAvailabilityMessage && model.offer.getId().equals(((OfferMessage) message).offerId))
|
if (message instanceof OfferAvailabilityResponse && model.offer.getId().equals(((OfferMessage) message).offerId))
|
||||||
handleDecryptedMessage((ReportOfferAvailabilityMessage) message);
|
handleDecryptedMessage((OfferAvailabilityResponse) message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void handleDecryptedMessage(ReportOfferAvailabilityMessage message) {
|
private void handleDecryptedMessage(OfferAvailabilityResponse message) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
model.setMessage(message);
|
model.setMessage(message);
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ public class CheckOfferAvailabilityProtocol {
|
||||||
errorMessageHandler.handleErrorMessage(errorMessage);
|
errorMessageHandler.handleErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
taskRunner.addTasks(ProcessReportOfferAvailabilityMessage.class);
|
taskRunner.addTasks(ProcessOfferAvailabilityResponse.class);
|
||||||
taskRunner.run();
|
taskRunner.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,22 +18,29 @@
|
||||||
package io.bitsquare.trade.protocol.availability.messages;
|
package io.bitsquare.trade.protocol.availability.messages;
|
||||||
|
|
||||||
import io.bitsquare.crypto.PubKeyRing;
|
import io.bitsquare.crypto.PubKeyRing;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class RequestIsOfferAvailableMessage extends TradeMessage implements Serializable {
|
public class OfferAvailabilityRequest extends OfferMessage implements Serializable {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final PubKeyRing pubKeyRing;
|
private final PubKeyRing pubKeyRing;
|
||||||
|
|
||||||
public RequestIsOfferAvailableMessage(String tradeId, PubKeyRing pubKeyRing) {
|
public OfferAvailabilityRequest(String offerId, PubKeyRing pubKeyRing) {
|
||||||
super(tradeId);
|
super(offerId);
|
||||||
this.pubKeyRing = pubKeyRing;
|
this.pubKeyRing = pubKeyRing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PubKeyRing getPubKeyRing() {
|
public PubKeyRing getPubKeyRing() {
|
||||||
return pubKeyRing;
|
return pubKeyRing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RequestIsOfferAvailableMessage{" +
|
||||||
|
"offerId=" + offerId +
|
||||||
|
"pubKeyRing=" + pubKeyRing != null ? pubKeyRing.toString() : "null" +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -19,14 +19,14 @@ package io.bitsquare.trade.protocol.availability.messages;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class ReportOfferAvailabilityMessage extends OfferMessage implements Serializable {
|
public class OfferAvailabilityResponse extends OfferMessage implements Serializable {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public final boolean isOfferOpen;
|
public final boolean isAvailable;
|
||||||
|
|
||||||
public ReportOfferAvailabilityMessage(String offerId, boolean isOfferOpen) {
|
public OfferAvailabilityResponse(String offerId, boolean isAvailable) {
|
||||||
super(offerId);
|
super(offerId);
|
||||||
this.isOfferOpen = isOfferOpen;
|
this.isAvailable = isAvailable;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,18 +19,18 @@ package io.bitsquare.trade.protocol.availability.tasks;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.Task;
|
import io.bitsquare.common.taskrunner.Task;
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.p2p.listener.GetPeerAddressListener;
|
import io.bitsquare.p2p.listener.GetPeerAddressListener;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityModel;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
|
public class GetPeerAddress extends Task<OfferAvailabilityModel> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
|
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
|
||||||
|
|
||||||
public GetPeerAddress(TaskRunner taskHandler, CheckOfferAvailabilityModel model) {
|
public GetPeerAddress(TaskRunner taskHandler, OfferAvailabilityModel model) {
|
||||||
super(taskHandler, model);
|
super(taskHandler, model);
|
||||||
|
|
||||||
errorMessage = "DHT lookup for peer address failed. Maybe the offerer was offline for too long time.";
|
errorMessage = "DHT lookup for peer address failed. Maybe the offerer was offline for too long time.";
|
||||||
|
@ -55,8 +55,6 @@ public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
model.offer.setState(Offer.State.FAULT);
|
|
||||||
|
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,36 +19,34 @@ package io.bitsquare.trade.protocol.availability.tasks;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.Task;
|
import io.bitsquare.common.taskrunner.Task;
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityModel;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
import io.bitsquare.trade.protocol.availability.messages.OfferAvailabilityResponse;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class ProcessReportOfferAvailabilityMessage extends Task<CheckOfferAvailabilityModel> {
|
public class ProcessOfferAvailabilityResponse extends Task<OfferAvailabilityModel> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(ProcessReportOfferAvailabilityMessage.class);
|
private static final Logger log = LoggerFactory.getLogger(ProcessOfferAvailabilityResponse.class);
|
||||||
|
|
||||||
public ProcessReportOfferAvailabilityMessage(TaskRunner taskHandler, CheckOfferAvailabilityModel model) {
|
public ProcessOfferAvailabilityResponse(TaskRunner taskHandler, OfferAvailabilityModel model) {
|
||||||
super(taskHandler, model);
|
super(taskHandler, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = (ReportOfferAvailabilityMessage) model.getMessage();
|
OfferAvailabilityResponse offerAvailabilityResponse = (OfferAvailabilityResponse) model.getMessage();
|
||||||
|
|
||||||
if (model.offer.getState() != Offer.State.REMOVED) {
|
if (model.offer.getState() != Offer.State.REMOVED) {
|
||||||
if (reportOfferAvailabilityMessage.isOfferOpen)
|
if (offerAvailabilityResponse.isAvailable)
|
||||||
model.offer.setState(Offer.State.AVAILABLE);
|
model.offer.setState(Offer.State.AVAILABLE);
|
||||||
else
|
else
|
||||||
model.offer.setState(Offer.State.RESERVED);
|
model.offer.setState(Offer.State.NOT_AVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
model.offer.setState(Offer.State.FAULT);
|
|
||||||
|
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,26 +19,25 @@ package io.bitsquare.trade.protocol.availability.tasks;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.Task;
|
import io.bitsquare.common.taskrunner.Task;
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityModel;
|
||||||
|
import io.bitsquare.trade.protocol.availability.messages.OfferAvailabilityRequest;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class SendRequestIsOfferAvailableMessage extends Task<CheckOfferAvailabilityModel> {
|
public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SendRequestIsOfferAvailableMessage.class);
|
private static final Logger log = LoggerFactory.getLogger(SendOfferAvailabilityRequest.class);
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public SendRequestIsOfferAvailableMessage(TaskRunner taskHandler, CheckOfferAvailabilityModel model) {
|
public SendOfferAvailabilityRequest(TaskRunner taskHandler, OfferAvailabilityModel model) {
|
||||||
super(taskHandler, model);
|
super(taskHandler, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
RequestIsOfferAvailableMessage message = new RequestIsOfferAvailableMessage(model.offer.getId(), model.getPubKeyRing());
|
OfferAvailabilityRequest message = new OfferAvailabilityRequest(model.offer.getId(), model.getPubKeyRing());
|
||||||
model.messageService.sendEncryptedMessage(model.getPeer(),
|
model.messageService.sendEncryptedMessage(model.getPeer(),
|
||||||
model.offer.getPubKeyRing(),
|
model.offer.getPubKeyRing(),
|
||||||
message,
|
message,
|
||||||
|
@ -56,8 +55,6 @@ public class SendRequestIsOfferAvailableMessage extends Task<CheckOfferAvailabil
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
model.offer.setState(Offer.State.FAULT);
|
|
||||||
|
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,8 +20,8 @@ package io.bitsquare.trade.protocol.placeoffer;
|
||||||
import io.bitsquare.btc.TradeWalletService;
|
import io.bitsquare.btc.TradeWalletService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.common.taskrunner.Model;
|
import io.bitsquare.common.taskrunner.Model;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.offer.OfferBookService;
|
import io.bitsquare.trade.offer.OfferBookService;
|
||||||
|
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,8 @@ package io.bitsquare.trade.protocol.trade;
|
||||||
|
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
|
||||||
import io.bitsquare.trade.BuyerAsOffererTrade;
|
import io.bitsquare.trade.BuyerAsOffererTrade;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
|
||||||
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
|
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestFinalizePayoutTxMessage;
|
import io.bitsquare.trade.protocol.trade.messages.RequestFinalizePayoutTxMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
|
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
|
@ -43,7 +39,6 @@ import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakeOfferFeePayment
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakerAccount;
|
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakerAccount;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.shared.CommitPayoutTx;
|
import io.bitsquare.trade.protocol.trade.tasks.shared.CommitPayoutTx;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||||
import io.bitsquare.trade.states.OffererTradeState;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -72,6 +67,26 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||||
// Public methods
|
// Public methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleTakeOfferRequest(TradeMessage message, Peer taker) {
|
||||||
|
checkTradeId(processModel.getId(), message);
|
||||||
|
processModel.setTradeMessage(message);
|
||||||
|
buyerAsOffererTrade.setTradingPeer(taker);
|
||||||
|
|
||||||
|
//buyerAsOffererTrade.setLifeCycleState(OffererTradeState.LifeCycleState.OFFER_RESERVED);
|
||||||
|
|
||||||
|
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsOffererTrade,
|
||||||
|
() -> log.debug("taskRunner at handleRequestDepositTxInputsMessage completed"),
|
||||||
|
this::handleTaskRunnerFault);
|
||||||
|
taskRunner.addTasks(
|
||||||
|
ProcessRequestDepositTxInputsMessage.class,
|
||||||
|
CreateDepositTxInputs.class,
|
||||||
|
SendRequestPayDepositMessage.class
|
||||||
|
);
|
||||||
|
taskRunner.run();
|
||||||
|
startTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doApplyMailboxMessage(Message message, Trade trade) {
|
public void doApplyMailboxMessage(Message message, Trade trade) {
|
||||||
this.trade = trade;
|
this.trade = trade;
|
||||||
|
@ -93,61 +108,6 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||||
// Incoming message handling
|
// Incoming message handling
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// OpenOffer requests
|
|
||||||
// We get an encrypted message but don't do the signature check as we don't know the peer yet.
|
|
||||||
// A basic sig check is in done also at decryption time
|
|
||||||
private void handle(RequestIsOfferAvailableMessage message, Peer sender) {
|
|
||||||
try {
|
|
||||||
checkTradeId(processModel.getId(), message);
|
|
||||||
|
|
||||||
// We don't store anything in the offererTradeProcessModel as we might be in a trade process and receive that request from another peer who wants
|
|
||||||
// to take the offer at the same time
|
|
||||||
boolean isOfferOpen = buyerAsOffererTrade.lifeCycleStateProperty().get() == OffererTradeState.LifeCycleState.OFFER_OPEN;
|
|
||||||
|
|
||||||
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(processModel.getId(), isOfferOpen);
|
|
||||||
processModel.getMessageService().sendEncryptedMessage(sender,
|
|
||||||
message.getPubKeyRing(),
|
|
||||||
reportOfferAvailabilityMessage,
|
|
||||||
new SendMessageListener() {
|
|
||||||
@Override
|
|
||||||
public void handleResult() {
|
|
||||||
// Offerer does not do anything at that moment. Peer might only watch the offer and does not start a trade.
|
|
||||||
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleFault() {
|
|
||||||
// We don't handle the error as we might be in a trade process with another trader
|
|
||||||
log.warn("Sending ReportOfferAvailabilityMessage failed.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
// We don't handle the error as we might be in a trade process with another trader
|
|
||||||
t.printStackTrace();
|
|
||||||
log.warn("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trade started. We reserve the offer for that taker. If anything goes wrong we reset the offer as open.
|
|
||||||
private void handle(RequestDepositTxInputsMessage tradeMessage, Peer taker) {
|
|
||||||
checkTradeId(processModel.getId(), tradeMessage);
|
|
||||||
processModel.setTradeMessage(tradeMessage);
|
|
||||||
buyerAsOffererTrade.setTradingPeer(taker);
|
|
||||||
|
|
||||||
buyerAsOffererTrade.setLifeCycleState(OffererTradeState.LifeCycleState.OFFER_RESERVED);
|
|
||||||
|
|
||||||
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsOffererTrade,
|
|
||||||
() -> log.debug("taskRunner at handleRequestDepositTxInputsMessage completed"),
|
|
||||||
this::handleTaskRunnerFault);
|
|
||||||
taskRunner.addTasks(
|
|
||||||
ProcessRequestDepositTxInputsMessage.class,
|
|
||||||
CreateDepositTxInputs.class,
|
|
||||||
SendRequestPayDepositMessage.class
|
|
||||||
);
|
|
||||||
taskRunner.run();
|
|
||||||
startTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handle(RequestPublishDepositTxMessage tradeMessage) {
|
private void handle(RequestPublishDepositTxMessage tradeMessage) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
processModel.setTradeMessage(tradeMessage);
|
processModel.setTradeMessage(tradeMessage);
|
||||||
|
@ -217,13 +177,7 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doHandleDecryptedMessage(TradeMessage tradeMessage, Peer sender) {
|
protected void doHandleDecryptedMessage(TradeMessage tradeMessage, Peer sender) {
|
||||||
if (tradeMessage instanceof RequestIsOfferAvailableMessage) {
|
if (tradeMessage instanceof RequestPublishDepositTxMessage) {
|
||||||
handle((RequestIsOfferAvailableMessage) tradeMessage, sender);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof RequestDepositTxInputsMessage) {
|
|
||||||
handle((RequestDepositTxInputsMessage) tradeMessage, sender);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof RequestPublishDepositTxMessage) {
|
|
||||||
handle((RequestPublishDepositTxMessage) tradeMessage);
|
handle((RequestPublishDepositTxMessage) tradeMessage);
|
||||||
}
|
}
|
||||||
else if (tradeMessage instanceof RequestFinalizePayoutTxMessage) {
|
else if (tradeMessage instanceof RequestFinalizePayoutTxMessage) {
|
||||||
|
|
|
@ -17,5 +17,9 @@
|
||||||
|
|
||||||
package io.bitsquare.trade.protocol.trade;
|
package io.bitsquare.trade.protocol.trade;
|
||||||
|
|
||||||
|
import io.bitsquare.p2p.Peer;
|
||||||
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
|
|
||||||
public interface OffererProtocol {
|
public interface OffererProtocol {
|
||||||
|
void handleTakeOfferRequest(TradeMessage message, Peer taker);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,9 @@ import io.bitsquare.crypto.CryptoService;
|
||||||
import io.bitsquare.crypto.KeyRing;
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.crypto.PubKeyRing;
|
import io.bitsquare.crypto.PubKeyRing;
|
||||||
import io.bitsquare.fiat.FiatAccount;
|
import io.bitsquare.fiat.FiatAccount;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.p2p.AddressService;
|
import io.bitsquare.p2p.AddressService;
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,11 @@ package io.bitsquare.trade.protocol.trade;
|
||||||
|
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
|
||||||
import io.bitsquare.trade.SellerAsOffererTrade;
|
import io.bitsquare.trade.SellerAsOffererTrade;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
|
||||||
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
|
||||||
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxFinalizedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.PayoutTxFinalizedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
|
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakeOfferFeePayment;
|
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakeOfferFeePayment;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakerAccount;
|
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakerAccount;
|
||||||
|
@ -43,13 +39,10 @@ import io.bitsquare.trade.protocol.trade.tasks.seller.SendRequestPublishDepositT
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SignPayoutTx;
|
import io.bitsquare.trade.protocol.trade.tasks.seller.SignPayoutTx;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.shared.CommitPayoutTx;
|
import io.bitsquare.trade.protocol.trade.tasks.shared.CommitPayoutTx;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||||
import io.bitsquare.trade.states.OffererTradeState;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static io.bitsquare.util.Validator.checkTradeId;
|
|
||||||
|
|
||||||
public class SellerAsOffererProtocol extends TradeProtocol implements SellerProtocol, OffererProtocol {
|
public class SellerAsOffererProtocol extends TradeProtocol implements SellerProtocol, OffererProtocol {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SellerAsOffererProtocol.class);
|
private static final Logger log = LoggerFactory.getLogger(SellerAsOffererProtocol.class);
|
||||||
|
|
||||||
|
@ -72,6 +65,26 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
||||||
// Public methods
|
// Public methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleTakeOfferRequest(TradeMessage message, Peer taker) {
|
||||||
|
processModel.setTradeMessage(message);
|
||||||
|
sellerAsOffererTrade.setTradingPeer(taker);
|
||||||
|
|
||||||
|
TradeTaskRunner taskRunner = new TradeTaskRunner(sellerAsOffererTrade,
|
||||||
|
() -> log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"),
|
||||||
|
this::handleTaskRunnerFault);
|
||||||
|
|
||||||
|
taskRunner.addTasks(
|
||||||
|
ProcessRequestPayDepositMessage.class,
|
||||||
|
VerifyTakerAccount.class,
|
||||||
|
CreateAndSignContract.class,
|
||||||
|
CreateAndSignDepositTx.class,
|
||||||
|
SendRequestPublishDepositTxMessage.class
|
||||||
|
);
|
||||||
|
taskRunner.run();
|
||||||
|
startTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doApplyMailboxMessage(Message message, Trade trade) {
|
public void doApplyMailboxMessage(Message message, Trade trade) {
|
||||||
this.trade = trade;
|
this.trade = trade;
|
||||||
|
@ -101,67 +114,6 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
||||||
// Incoming message handling
|
// Incoming message handling
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// IsOfferAvailable
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private void handle(RequestIsOfferAvailableMessage message, Peer sender) {
|
|
||||||
try {
|
|
||||||
checkTradeId(processModel.getId(), message);
|
|
||||||
|
|
||||||
// We don't store anything in the offererTradeProcessModel as we might be in a trade process and receive that request from another peer who wants
|
|
||||||
// to take the offer at the same time
|
|
||||||
boolean isOfferOpen = sellerAsOffererTrade.lifeCycleStateProperty().get() == OffererTradeState.LifeCycleState.OFFER_OPEN;
|
|
||||||
|
|
||||||
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(processModel.getId(), isOfferOpen);
|
|
||||||
processModel.getMessageService().sendEncryptedMessage(sender,
|
|
||||||
message.getPubKeyRing(),
|
|
||||||
reportOfferAvailabilityMessage,
|
|
||||||
new SendMessageListener() {
|
|
||||||
@Override
|
|
||||||
public void handleResult() {
|
|
||||||
// Offerer does not do anything at that moment. Peer might only watch the offer and does not start a trade.
|
|
||||||
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleFault() {
|
|
||||||
// We don't handle the error as we might be in a trade process with another trader
|
|
||||||
log.warn("Sending ReportOfferAvailabilityMessage failed.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
// We don't handle the error as we might be in a trade process with another trader
|
|
||||||
t.printStackTrace();
|
|
||||||
log.warn("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Trade
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private void handle(RequestPayDepositMessage tradeMessage, Peer sender) {
|
|
||||||
processModel.setTradeMessage(tradeMessage);
|
|
||||||
|
|
||||||
sellerAsOffererTrade.setTradingPeer(sender);
|
|
||||||
|
|
||||||
TradeTaskRunner taskRunner = new TradeTaskRunner(sellerAsOffererTrade,
|
|
||||||
() -> log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"),
|
|
||||||
this::handleTaskRunnerFault);
|
|
||||||
|
|
||||||
taskRunner.addTasks(
|
|
||||||
ProcessRequestPayDepositMessage.class,
|
|
||||||
VerifyTakerAccount.class,
|
|
||||||
CreateAndSignContract.class,
|
|
||||||
CreateAndSignDepositTx.class,
|
|
||||||
SendRequestPublishDepositTxMessage.class
|
|
||||||
);
|
|
||||||
taskRunner.run();
|
|
||||||
startTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handle(DepositTxPublishedMessage tradeMessage) {
|
private void handle(DepositTxPublishedMessage tradeMessage) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
processModel.setTradeMessage(tradeMessage);
|
processModel.setTradeMessage(tradeMessage);
|
||||||
|
@ -239,13 +191,7 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doHandleDecryptedMessage(TradeMessage tradeMessage, Peer sender) {
|
protected void doHandleDecryptedMessage(TradeMessage tradeMessage, Peer sender) {
|
||||||
if (tradeMessage instanceof RequestIsOfferAvailableMessage) {
|
if (tradeMessage instanceof DepositTxPublishedMessage) {
|
||||||
handle((RequestIsOfferAvailableMessage) tradeMessage, sender);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof RequestPayDepositMessage) {
|
|
||||||
handle((RequestPayDepositMessage) tradeMessage, sender);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof DepositTxPublishedMessage) {
|
|
||||||
handle((DepositTxPublishedMessage) tradeMessage);
|
handle((DepositTxPublishedMessage) tradeMessage);
|
||||||
}
|
}
|
||||||
else if (tradeMessage instanceof FiatTransferStartedMessage) {
|
else if (tradeMessage instanceof FiatTransferStartedMessage) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ public class RequestPayDepositMessage extends TradeMessage implements Serializab
|
||||||
public final List<TransactionOutput> buyerConnectedOutputsForAllInputs;
|
public final List<TransactionOutput> buyerConnectedOutputsForAllInputs;
|
||||||
public final List<TransactionOutput> buyerOutputs;
|
public final List<TransactionOutput> buyerOutputs;
|
||||||
public final byte[] buyerTradeWalletPubKey;
|
public final byte[] buyerTradeWalletPubKey;
|
||||||
|
public final boolean isInitialRequest;
|
||||||
public final PubKeyRing buyerPubKeyRing;
|
public final PubKeyRing buyerPubKeyRing;
|
||||||
public final FiatAccount buyerFiatAccount;
|
public final FiatAccount buyerFiatAccount;
|
||||||
public final String buyerAccountId;
|
public final String buyerAccountId;
|
||||||
|
@ -44,6 +45,7 @@ public class RequestPayDepositMessage extends TradeMessage implements Serializab
|
||||||
|
|
||||||
public RequestPayDepositMessage(String tradeId,
|
public RequestPayDepositMessage(String tradeId,
|
||||||
Coin tradeAmount,
|
Coin tradeAmount,
|
||||||
|
boolean isInitialRequest,
|
||||||
List<TransactionOutput> buyerConnectedOutputsForAllInputs,
|
List<TransactionOutput> buyerConnectedOutputsForAllInputs,
|
||||||
List<TransactionOutput> buyerOutputs,
|
List<TransactionOutput> buyerOutputs,
|
||||||
byte[] buyerTradeWalletPubKey,
|
byte[] buyerTradeWalletPubKey,
|
||||||
|
@ -52,6 +54,7 @@ public class RequestPayDepositMessage extends TradeMessage implements Serializab
|
||||||
String buyerAccountId) {
|
String buyerAccountId) {
|
||||||
super(tradeId);
|
super(tradeId);
|
||||||
this.tradeAmount = tradeAmount;
|
this.tradeAmount = tradeAmount;
|
||||||
|
this.isInitialRequest = isInitialRequest;
|
||||||
this.buyerPubKeyRing = buyerPubKeyRing;
|
this.buyerPubKeyRing = buyerPubKeyRing;
|
||||||
this.buyerConnectedOutputsForAllInputs = buyerConnectedOutputsForAllInputs;
|
this.buyerConnectedOutputsForAllInputs = buyerConnectedOutputsForAllInputs;
|
||||||
this.buyerOutputs = buyerOutputs;
|
this.buyerOutputs = buyerOutputs;
|
||||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.trade.protocol.trade.tasks.buyer;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||||
|
import io.bitsquare.trade.BuyerAsTakerTrade;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.trade.TradeTask;
|
import io.bitsquare.trade.protocol.trade.TradeTask;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
|
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
|
||||||
|
@ -37,9 +38,11 @@ public class SendRequestPayDepositMessage extends TradeTask {
|
||||||
@Override
|
@Override
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
|
boolean isInitialRequest = trade instanceof BuyerAsTakerTrade;
|
||||||
RequestPayDepositMessage tradeMessage = new RequestPayDepositMessage(
|
RequestPayDepositMessage tradeMessage = new RequestPayDepositMessage(
|
||||||
processModel.getId(),
|
processModel.getId(),
|
||||||
trade.getTradeAmount(),
|
trade.getTradeAmount(),
|
||||||
|
isInitialRequest,
|
||||||
processModel.getConnectedOutputsForAllInputs(),
|
processModel.getConnectedOutputsForAllInputs(),
|
||||||
processModel.getOutputs(),
|
processModel.getOutputs(),
|
||||||
processModel.getTradeWalletPubKey(),
|
processModel.getTradeWalletPubKey(),
|
||||||
|
|
|
@ -66,14 +66,11 @@ public class SignAndPublishDepositTx extends TradeTask {
|
||||||
|
|
||||||
trade.setDepositTx(transaction);
|
trade.setDepositTx(transaction);
|
||||||
|
|
||||||
if (trade instanceof TakerTrade) {
|
trade.setLifeCycleState(Trade.LifeCycleState.PENDING);
|
||||||
|
if (trade instanceof TakerTrade)
|
||||||
trade.setProcessState(TakerTradeState.ProcessState.DEPOSIT_PUBLISHED);
|
trade.setProcessState(TakerTradeState.ProcessState.DEPOSIT_PUBLISHED);
|
||||||
trade.setLifeCycleState(TakerTradeState.LifeCycleState.PENDING);
|
else if (trade instanceof OffererTrade)
|
||||||
}
|
|
||||||
else if (trade instanceof OffererTrade) {
|
|
||||||
trade.setProcessState(OffererTradeState.ProcessState.DEPOSIT_PUBLISHED);
|
trade.setProcessState(OffererTradeState.ProcessState.DEPOSIT_PUBLISHED);
|
||||||
trade.setLifeCycleState(OffererTradeState.LifeCycleState.PENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
trade.setTakeOfferDate(new Date());
|
trade.setTakeOfferDate(new Date());
|
||||||
|
|
||||||
|
@ -95,7 +92,7 @@ public class SignAndPublishDepositTx extends TradeTask {
|
||||||
trade.setThrowable(t);
|
trade.setThrowable(t);
|
||||||
|
|
||||||
if (trade instanceof OffererTrade)
|
if (trade instanceof OffererTrade)
|
||||||
trade.setLifeCycleState(OffererTradeState.LifeCycleState.OFFER_OPEN);
|
trade.setLifeCycleState(Trade.LifeCycleState.PREPARATION);
|
||||||
|
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,15 +23,6 @@ import org.slf4j.LoggerFactory;
|
||||||
public class OffererTradeState {
|
public class OffererTradeState {
|
||||||
private static final Logger log = LoggerFactory.getLogger(OffererTradeState.class);
|
private static final Logger log = LoggerFactory.getLogger(OffererTradeState.class);
|
||||||
|
|
||||||
public enum LifeCycleState implements TradeState.LifeCycleState {
|
|
||||||
OFFER_OPEN,
|
|
||||||
OFFER_RESERVED,
|
|
||||||
OFFER_CANCELED,
|
|
||||||
PENDING,
|
|
||||||
COMPLETED,
|
|
||||||
FAILED
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ProcessState implements TradeState.ProcessState {
|
public enum ProcessState implements TradeState.ProcessState {
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
DEPOSIT_PUBLISHED,
|
DEPOSIT_PUBLISHED,
|
||||||
|
|
|
@ -36,6 +36,6 @@ public class StateUtil {
|
||||||
|
|
||||||
public static void setOfferOpenState(Trade trade) {
|
public static void setOfferOpenState(Trade trade) {
|
||||||
if (trade instanceof OffererTrade)
|
if (trade instanceof OffererTrade)
|
||||||
trade.setLifeCycleState(OffererTradeState.LifeCycleState.OFFER_OPEN);
|
trade.setLifeCycleState(Trade.LifeCycleState.PREPARATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,6 @@ import org.slf4j.LoggerFactory;
|
||||||
public class TakerTradeState {
|
public class TakerTradeState {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TakerTradeState.class);
|
private static final Logger log = LoggerFactory.getLogger(TakerTradeState.class);
|
||||||
|
|
||||||
public enum LifeCycleState implements TradeState.LifeCycleState {
|
|
||||||
PENDING,
|
|
||||||
COMPLETED,
|
|
||||||
FAILED
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ProcessState implements TradeState.ProcessState {
|
public enum ProcessState implements TradeState.ProcessState {
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
TAKE_OFFER_FEE_TX_CREATED,
|
TAKE_OFFER_FEE_TX_CREATED,
|
||||||
|
|
|
@ -23,9 +23,6 @@ import org.slf4j.LoggerFactory;
|
||||||
public class TradeState {
|
public class TradeState {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TradeState.class);
|
private static final Logger log = LoggerFactory.getLogger(TradeState.class);
|
||||||
|
|
||||||
public interface LifeCycleState {
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ProcessState {
|
public interface ProcessState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
package io.bitsquare.trade.protocol.placeoffer;
|
package io.bitsquare.trade.protocol.placeoffer;
|
||||||
|
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.offer.OfferBookService;
|
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
|
import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
|
||||||
import io.bitsquare.p2p.tomp2p.TomP2PNode;
|
import io.bitsquare.p2p.tomp2p.TomP2PNode;
|
||||||
|
import io.bitsquare.trade.offer.OfferBookService;
|
||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,12 @@ import io.bitsquare.crypto.CryptoModule;
|
||||||
import io.bitsquare.crypto.KeyRing;
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.crypto.KeyStorage;
|
import io.bitsquare.crypto.KeyStorage;
|
||||||
import io.bitsquare.gui.GuiModule;
|
import io.bitsquare.gui.GuiModule;
|
||||||
import io.bitsquare.offer.OfferModule;
|
|
||||||
import io.bitsquare.offer.tomp2p.TomP2POfferModule;
|
|
||||||
import io.bitsquare.p2p.P2PModule;
|
import io.bitsquare.p2p.P2PModule;
|
||||||
import io.bitsquare.p2p.tomp2p.TomP2PModule;
|
import io.bitsquare.p2p.tomp2p.TomP2PModule;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
import io.bitsquare.trade.TradeModule;
|
import io.bitsquare.trade.TradeModule;
|
||||||
|
import io.bitsquare.trade.offer.OfferModule;
|
||||||
|
import io.bitsquare.trade.offer.tomp2p.TomP2POfferModule;
|
||||||
import io.bitsquare.user.AccountSettings;
|
import io.bitsquare.user.AccountSettings;
|
||||||
import io.bitsquare.user.Preferences;
|
import io.bitsquare.user.Preferences;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
|
@ -31,6 +31,7 @@ import io.bitsquare.p2p.BootstrapState;
|
||||||
import io.bitsquare.p2p.ClientNode;
|
import io.bitsquare.p2p.ClientNode;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
@ -91,12 +92,13 @@ class MainViewModel implements ViewModel {
|
||||||
private final ArbitrationRepository arbitrationRepository;
|
private final ArbitrationRepository arbitrationRepository;
|
||||||
private final ClientNode clientNode;
|
private final ClientNode clientNode;
|
||||||
private final TradeManager tradeManager;
|
private final TradeManager tradeManager;
|
||||||
|
private OpenOfferManager openOfferManager;
|
||||||
private final UpdateProcess updateProcess;
|
private final UpdateProcess updateProcess;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MainViewModel(User user, KeyRing keyRing, WalletService walletService, ArbitrationRepository arbitrationRepository, ClientNode clientNode,
|
public MainViewModel(User user, KeyRing keyRing, WalletService walletService, ArbitrationRepository arbitrationRepository, ClientNode clientNode,
|
||||||
TradeManager tradeManager, BitcoinNetwork bitcoinNetwork, UpdateProcess updateProcess,
|
TradeManager tradeManager, OpenOfferManager openOfferManager, BitcoinNetwork bitcoinNetwork, UpdateProcess updateProcess,
|
||||||
BSFormatter formatter) {
|
BSFormatter formatter) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
|
@ -104,6 +106,7 @@ class MainViewModel implements ViewModel {
|
||||||
this.arbitrationRepository = arbitrationRepository;
|
this.arbitrationRepository = arbitrationRepository;
|
||||||
this.clientNode = clientNode;
|
this.clientNode = clientNode;
|
||||||
this.tradeManager = tradeManager;
|
this.tradeManager = tradeManager;
|
||||||
|
this.openOfferManager = openOfferManager;
|
||||||
this.updateProcess = updateProcess;
|
this.updateProcess = updateProcess;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
|
|
||||||
|
@ -211,6 +214,7 @@ class MainViewModel implements ViewModel {
|
||||||
log.debug("loadAllArbitrators");
|
log.debug("loadAllArbitrators");
|
||||||
arbitrationRepository.loadAllArbitrators();
|
arbitrationRepository.loadAllArbitrators();
|
||||||
tradeManager.onAllServicesInitialized();
|
tradeManager.onAllServicesInitialized();
|
||||||
|
openOfferManager.onAllServicesInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyUpdateState(UpdateProcess.State state) {
|
private void applyUpdateState(UpdateProcess.State state) {
|
||||||
|
|
|
@ -20,9 +20,9 @@ package io.bitsquare.gui.main.debug;
|
||||||
import io.bitsquare.common.taskrunner.Task;
|
import io.bitsquare.common.taskrunner.Task;
|
||||||
import io.bitsquare.gui.common.view.FxmlView;
|
import io.bitsquare.gui.common.view.FxmlView;
|
||||||
import io.bitsquare.gui.common.view.InitializableView;
|
import io.bitsquare.gui.common.view.InitializableView;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityProtocol;
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityProtocol;
|
||||||
import io.bitsquare.trade.protocol.availability.tasks.ProcessReportOfferAvailabilityMessage;
|
import io.bitsquare.trade.protocol.availability.tasks.ProcessOfferAvailabilityResponse;
|
||||||
import io.bitsquare.trade.protocol.availability.tasks.SendRequestIsOfferAvailableMessage;
|
import io.bitsquare.trade.protocol.availability.tasks.SendOfferAvailabilityRequest;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.tasks.AddOfferToRemoteOfferBook;
|
import io.bitsquare.trade.protocol.placeoffer.tasks.AddOfferToRemoteOfferBook;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.tasks.BroadcastCreateOfferFeeTx;
|
import io.bitsquare.trade.protocol.placeoffer.tasks.BroadcastCreateOfferFeeTx;
|
||||||
|
@ -80,10 +80,10 @@ public class DebugView extends InitializableView {
|
||||||
|
|
||||||
final ObservableList<Class> items = FXCollections.observableArrayList(Arrays.asList(
|
final ObservableList<Class> items = FXCollections.observableArrayList(Arrays.asList(
|
||||||
/*---- Protocol ----*/
|
/*---- Protocol ----*/
|
||||||
CheckOfferAvailabilityProtocol.class,
|
OfferAvailabilityProtocol.class,
|
||||||
io.bitsquare.trade.protocol.availability.tasks.GetPeerAddress.class,
|
io.bitsquare.trade.protocol.availability.tasks.GetPeerAddress.class,
|
||||||
SendRequestIsOfferAvailableMessage.class,
|
SendOfferAvailabilityRequest.class,
|
||||||
ProcessReportOfferAvailabilityMessage.class,
|
ProcessOfferAvailabilityResponse.class,
|
||||||
Boolean.class, /* used as seperator*/
|
Boolean.class, /* used as seperator*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import io.bitsquare.gui.common.view.FxmlView;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.gui.util.GUIUtil;
|
import io.bitsquare.gui.util.GUIUtil;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
|
@ -51,13 +52,15 @@ public class ReservedView extends ActivatableViewAndModel {
|
||||||
|
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private final TradeManager tradeManager;
|
private final TradeManager tradeManager;
|
||||||
|
private OpenOfferManager openOfferManager;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final ObservableList<ReservedListItem> addressList = FXCollections.observableArrayList();
|
private final ObservableList<ReservedListItem> addressList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ReservedView(WalletService walletService, TradeManager tradeManager, BSFormatter formatter) {
|
private ReservedView(WalletService walletService, TradeManager tradeManager, OpenOfferManager openOfferManager, BSFormatter formatter) {
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.tradeManager = tradeManager;
|
this.tradeManager = tradeManager;
|
||||||
|
this.openOfferManager = openOfferManager;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +97,8 @@ public class ReservedView extends ActivatableViewAndModel {
|
||||||
|
|
||||||
private void fillList() {
|
private void fillList() {
|
||||||
addressList.clear();
|
addressList.clear();
|
||||||
addressList.addAll(Stream.concat(tradeManager.getOpenOfferTrades().stream(), tradeManager.getPendingTrades().stream())
|
addressList.addAll(Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getPendingTrades().stream())
|
||||||
.map(trade -> new ReservedListItem(walletService.getAddressEntry(trade.getId()), walletService, formatter))
|
.map(tradable -> new ReservedListItem(walletService.getAddressEntry(tradable.getOffer().getId()), walletService, formatter))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
// List<AddressEntry> addressEntryList = walletService.getAddressEntryList();
|
// List<AddressEntry> addressEntryList = walletService.getAddressEntryList();
|
||||||
|
|
|
@ -28,6 +28,7 @@ import io.bitsquare.gui.components.Popups;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.gui.util.GUIUtil;
|
import io.bitsquare.gui.util.GUIUtil;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
|
|
||||||
import org.bitcoinj.core.AddressFormatException;
|
import org.bitcoinj.core.AddressFormatException;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
@ -67,13 +68,15 @@ public class WithdrawalView extends ActivatableViewAndModel {
|
||||||
|
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private TradeManager tradeManager;
|
private TradeManager tradeManager;
|
||||||
|
private OpenOfferManager openOfferManager;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final ObservableList<WithdrawalListItem> addressList = FXCollections.observableArrayList();
|
private final ObservableList<WithdrawalListItem> addressList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private WithdrawalView(WalletService walletService, TradeManager tradeManager, BSFormatter formatter) {
|
private WithdrawalView(WalletService walletService, TradeManager tradeManager, OpenOfferManager openOfferManager, BSFormatter formatter) {
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.tradeManager = tradeManager;
|
this.tradeManager = tradeManager;
|
||||||
|
this.openOfferManager = openOfferManager;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +184,8 @@ public class WithdrawalView extends ActivatableViewAndModel {
|
||||||
addressList.clear();
|
addressList.clear();
|
||||||
List<AddressEntry> addressEntryList = walletService.getAddressEntryList();
|
List<AddressEntry> addressEntryList = walletService.getAddressEntryList();
|
||||||
|
|
||||||
List<String> reservedTrades = Stream.concat(tradeManager.getOpenOfferTrades().stream(), tradeManager.getPendingTrades().stream())
|
List<String> reservedTrades = Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getPendingTrades().stream())
|
||||||
.map(trade -> trade.getId())
|
.map(tradable -> tradable.getOffer().getId())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
addressList.addAll(addressEntryList.stream()
|
addressList.addAll(addressEntryList.stream()
|
||||||
|
|
|
@ -26,7 +26,7 @@ import io.bitsquare.gui.main.MainView;
|
||||||
import io.bitsquare.gui.main.offer.createoffer.CreateOfferView;
|
import io.bitsquare.gui.main.offer.createoffer.CreateOfferView;
|
||||||
import io.bitsquare.gui.main.offer.offerbook.OfferBookView;
|
import io.bitsquare.gui.main.offer.offerbook.OfferBookView;
|
||||||
import io.bitsquare.gui.main.offer.takeoffer.TakeOfferView;
|
import io.bitsquare.gui.main.offer.takeoffer.TakeOfferView;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.utils.Fiat;
|
import org.bitcoinj.utils.Fiat;
|
||||||
|
|
|
@ -28,8 +28,8 @@ import io.bitsquare.gui.common.model.Activatable;
|
||||||
import io.bitsquare.gui.common.model.DataModel;
|
import io.bitsquare.gui.common.model.DataModel;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.locale.Country;
|
import io.bitsquare.locale.Country;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
import io.bitsquare.user.AccountSettings;
|
import io.bitsquare.user.AccountSettings;
|
||||||
import io.bitsquare.user.Preferences;
|
import io.bitsquare.user.Preferences;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
@ -67,7 +67,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
class CreateOfferDataModel implements Activatable, DataModel {
|
class CreateOfferDataModel implements Activatable, DataModel {
|
||||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferDataModel.class);
|
private static final Logger log = LoggerFactory.getLogger(CreateOfferDataModel.class);
|
||||||
|
|
||||||
private final TradeManager tradeManager;
|
private OpenOfferManager openOfferManager;
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private final AccountSettings accountSettings;
|
private final AccountSettings accountSettings;
|
||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
|
@ -106,11 +106,10 @@ class CreateOfferDataModel implements Activatable, DataModel {
|
||||||
|
|
||||||
// non private for testing
|
// non private for testing
|
||||||
@Inject
|
@Inject
|
||||||
public CreateOfferDataModel(TradeManager tradeManager, WalletService walletService, ArbitratorService arbitratorService,
|
public CreateOfferDataModel(OpenOfferManager openOfferManager, WalletService walletService, ArbitratorService arbitratorService,
|
||||||
AccountSettings accountSettings, Preferences preferences, User user, BSFormatter formatter) {
|
AccountSettings accountSettings, Preferences preferences, User user, BSFormatter formatter) {
|
||||||
this.tradeManager = tradeManager;
|
this.openOfferManager = openOfferManager;
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
ArbitratorService arbitratorService1 = arbitratorService;
|
|
||||||
this.accountSettings = accountSettings;
|
this.accountSettings = accountSettings;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
|
@ -163,9 +162,9 @@ class CreateOfferDataModel implements Activatable, DataModel {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
void placeOffer() {
|
void onPlaceOffer() {
|
||||||
// data validation is done in the trade domain
|
// data validation is done in the trade domain
|
||||||
tradeManager.placeOffer(offerId,
|
openOfferManager.onPlaceOffer(offerId,
|
||||||
direction,
|
direction,
|
||||||
priceAsFiat.get(),
|
priceAsFiat.get(),
|
||||||
amountAsCoin.get(),
|
amountAsCoin.get(),
|
||||||
|
|
|
@ -38,7 +38,7 @@ import io.bitsquare.gui.main.portfolio.PortfolioView;
|
||||||
import io.bitsquare.gui.main.portfolio.openoffer.OpenOffersView;
|
import io.bitsquare.gui.main.portfolio.openoffer.OpenOffersView;
|
||||||
import io.bitsquare.gui.util.ImageUtil;
|
import io.bitsquare.gui.util.ImageUtil;
|
||||||
import io.bitsquare.locale.BSResources;
|
import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.utils.Fiat;
|
import org.bitcoinj.utils.Fiat;
|
||||||
|
@ -141,7 +141,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void onPlaceOffer() {
|
void onPlaceOffer() {
|
||||||
model.placeOffer();
|
model.onPlaceOffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
|
|
@ -25,7 +25,7 @@ import io.bitsquare.gui.util.validation.BtcValidator;
|
||||||
import io.bitsquare.gui.util.validation.FiatValidator;
|
import io.bitsquare.gui.util.validation.FiatValidator;
|
||||||
import io.bitsquare.gui.util.validation.InputValidator;
|
import io.bitsquare.gui.util.validation.InputValidator;
|
||||||
import io.bitsquare.locale.BSResources;
|
import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
@ -154,13 +154,13 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void placeOffer() {
|
void onPlaceOffer() {
|
||||||
dataModel.requestPlaceOfferErrorMessage.set(null);
|
dataModel.requestPlaceOfferErrorMessage.set(null);
|
||||||
dataModel.requestPlaceOfferSuccess.set(false);
|
dataModel.requestPlaceOfferSuccess.set(false);
|
||||||
|
|
||||||
isPlaceOfferSpinnerVisible.set(true);
|
isPlaceOfferSpinnerVisible.set(true);
|
||||||
|
|
||||||
dataModel.placeOffer();
|
dataModel.onPlaceOffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ import io.bitsquare.fiat.FiatAccount;
|
||||||
import io.bitsquare.gui.util.GUIUtil;
|
import io.bitsquare.gui.util.GUIUtil;
|
||||||
import io.bitsquare.locale.Country;
|
import io.bitsquare.locale.Country;
|
||||||
import io.bitsquare.locale.CurrencyUtil;
|
import io.bitsquare.locale.CurrencyUtil;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.offer.OfferBookService;
|
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
import io.bitsquare.trade.offer.OfferBookService;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -95,7 +95,7 @@ public class OfferBook {
|
||||||
// Update state in case that that offer is used in the take offer screen, so it gets updated correctly
|
// Update state in case that that offer is used in the take offer screen, so it gets updated correctly
|
||||||
offer.setState(Offer.State.REMOVED);
|
offer.setState(Offer.State.REMOVED);
|
||||||
|
|
||||||
// clean up possible references in tradeManager
|
// clean up possible references in openOfferManager
|
||||||
tradeManager.onOfferRemovedFromRemoteOfferBook(offer);
|
tradeManager.onOfferRemovedFromRemoteOfferBook(offer);
|
||||||
|
|
||||||
offerBookListItems.removeIf(item -> item.getOffer().getId().equals(offer.getId()));
|
offerBookListItems.removeIf(item -> item.getOffer().getId().equals(offer.getId()));
|
||||||
|
|
|
@ -25,8 +25,8 @@ import io.bitsquare.gui.common.model.DataModel;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.locale.Country;
|
import io.bitsquare.locale.Country;
|
||||||
import io.bitsquare.locale.CurrencyUtil;
|
import io.bitsquare.locale.CurrencyUtil;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
import io.bitsquare.user.Preferences;
|
import io.bitsquare.user.Preferences;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class OfferBookDataModel implements Activatable, DataModel {
|
||||||
private final OfferBook offerBook;
|
private final OfferBook offerBook;
|
||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final TradeManager tradeManager;
|
private final OpenOfferManager openOfferManager;
|
||||||
|
|
||||||
private final FilteredList<OfferBookListItem> filteredItems;
|
private final FilteredList<OfferBookListItem> filteredItems;
|
||||||
private final SortedList<OfferBookListItem> sortedItems;
|
private final SortedList<OfferBookListItem> sortedItems;
|
||||||
|
@ -77,9 +77,9 @@ class OfferBookDataModel implements Activatable, DataModel {
|
||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public OfferBookDataModel(User user, TradeManager tradeManager, OfferBook offerBook, Preferences preferences,
|
public OfferBookDataModel(User user, OpenOfferManager openOfferManager, OfferBook offerBook, Preferences preferences,
|
||||||
BSFormatter formatter) {
|
BSFormatter formatter) {
|
||||||
this.tradeManager = tradeManager;
|
this.openOfferManager = openOfferManager;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.offerBook = offerBook;
|
this.offerBook = offerBook;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
|
@ -112,7 +112,7 @@ class OfferBookDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
void onCancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
void onCancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
tradeManager.onCancelOpenOffer(offer, resultHandler, errorMessageHandler);
|
openOfferManager.onCancelOpenOffer(offer, resultHandler, errorMessageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateVolume() {
|
void calculateVolume() {
|
||||||
|
@ -210,7 +210,7 @@ class OfferBookDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMyOffer(Offer offer) {
|
boolean isMyOffer(Offer offer) {
|
||||||
return tradeManager.isMyOffer(offer);
|
return openOfferManager.isMyOffer(offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Coin getAmountAsCoin() {
|
Coin getAmountAsCoin() {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
package io.bitsquare.gui.main.offer.offerbook;
|
package io.bitsquare.gui.main.offer.offerbook;
|
||||||
|
|
||||||
import io.bitsquare.locale.Country;
|
import io.bitsquare.locale.Country;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
|
|
@ -35,7 +35,7 @@ import io.bitsquare.gui.util.ImageUtil;
|
||||||
import io.bitsquare.gui.util.validation.OptionalBtcValidator;
|
import io.bitsquare.gui.util.validation.OptionalBtcValidator;
|
||||||
import io.bitsquare.gui.util.validation.OptionalFiatValidator;
|
import io.bitsquare.gui.util.validation.OptionalFiatValidator;
|
||||||
import io.bitsquare.locale.BSResources;
|
import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import io.bitsquare.gui.util.validation.InputValidator;
|
||||||
import io.bitsquare.gui.util.validation.OptionalBtcValidator;
|
import io.bitsquare.gui.util.validation.OptionalBtcValidator;
|
||||||
import io.bitsquare.gui.util.validation.OptionalFiatValidator;
|
import io.bitsquare.gui.util.validation.OptionalFiatValidator;
|
||||||
import io.bitsquare.locale.BSResources;
|
import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.utils.Fiat;
|
import org.bitcoinj.utils.Fiat;
|
||||||
|
|
|
@ -23,9 +23,9 @@ import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
import io.bitsquare.gui.common.model.Activatable;
|
import io.bitsquare.gui.common.model.Activatable;
|
||||||
import io.bitsquare.gui.common.model.DataModel;
|
import io.bitsquare.gui.common.model.DataModel;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
import io.bitsquare.trade.handlers.TakeOfferResultHandler;
|
import io.bitsquare.trade.handlers.TakeOfferResultHandler;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.user.Preferences;
|
import io.bitsquare.user.Preferences;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
|
@ -36,7 +36,7 @@ import io.bitsquare.gui.main.portfolio.PortfolioView;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView;
|
||||||
import io.bitsquare.gui.util.ImageUtil;
|
import io.bitsquare.gui.util.ImageUtil;
|
||||||
import io.bitsquare.locale.BSResources;
|
import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@ import io.bitsquare.gui.util.validation.BtcValidator;
|
||||||
import io.bitsquare.gui.util.validation.InputValidator;
|
import io.bitsquare.gui.util.validation.InputValidator;
|
||||||
import io.bitsquare.locale.BSResources;
|
import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.locale.CurrencyUtil;
|
import io.bitsquare.locale.CurrencyUtil;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.trade.BuyerAsTakerTrade;
|
import io.bitsquare.trade.BuyerAsTakerTrade;
|
||||||
import io.bitsquare.trade.SellerAsTakerTrade;
|
import io.bitsquare.trade.SellerAsTakerTrade;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.states.TakerTradeState;
|
import io.bitsquare.trade.states.TakerTradeState;
|
||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
|
@ -173,13 +173,13 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
log.debug("offer state = " + state);
|
log.debug("offer state = " + state);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case UNKNOWN:
|
case UNDEFINED:
|
||||||
// TODO set spinner?
|
// TODO set spinner?
|
||||||
break;
|
break;
|
||||||
case AVAILABLE:
|
case AVAILABLE:
|
||||||
this.state.set(State.AMOUNT_SCREEN);
|
this.state.set(State.AMOUNT_SCREEN);
|
||||||
break;
|
break;
|
||||||
case RESERVED:
|
case NOT_AVAILABLE:
|
||||||
if (takeOfferRequested)
|
if (takeOfferRequested)
|
||||||
errorMessage.set("Take offer request failed because offer is not available anymore. " +
|
errorMessage.set("Take offer request failed because offer is not available anymore. " +
|
||||||
"Maybe another trader has taken the offer in the meantime.");
|
"Maybe another trader has taken the offer in the meantime.");
|
||||||
|
@ -200,14 +200,14 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
errorMessage.set("You cannot take that offer because the offerer is offline.");
|
errorMessage.set("You cannot take that offer because the offerer is offline.");
|
||||||
takeOfferRequested = false;
|
takeOfferRequested = false;
|
||||||
break;
|
break;
|
||||||
case FAULT:
|
/* case FAULT:
|
||||||
if (takeOfferRequested)
|
if (takeOfferRequested)
|
||||||
errorMessage.set("Take offer request failed.");
|
errorMessage.set("Take offer request failed.");
|
||||||
else
|
else
|
||||||
errorMessage.set("The check for the offer availability failed.");
|
errorMessage.set("The check for the offer availability failed.");
|
||||||
|
|
||||||
takeOfferRequested = false;
|
takeOfferRequested = false;
|
||||||
break;
|
break;*/
|
||||||
default:
|
default:
|
||||||
log.error("Unhandled offer state: " + state);
|
log.error("Unhandled offer state: " + state);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -19,10 +19,9 @@ package io.bitsquare.gui.main.portfolio.closedtrades;
|
||||||
|
|
||||||
import io.bitsquare.gui.common.model.Activatable;
|
import io.bitsquare.gui.common.model.Activatable;
|
||||||
import io.bitsquare.gui.common.model.DataModel;
|
import io.bitsquare.gui.common.model.DataModel;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.Tradable;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.user.User;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
@ -34,16 +33,14 @@ import javafx.collections.ObservableList;
|
||||||
|
|
||||||
class ClosedTradesDataModel implements Activatable, DataModel {
|
class ClosedTradesDataModel implements Activatable, DataModel {
|
||||||
|
|
||||||
private final TradeManager tradeManager;
|
private final ClosedTradableManager closedTradableManager;
|
||||||
private final User user;
|
|
||||||
|
|
||||||
private final ObservableList<ClosedTradesListItem> list = FXCollections.observableArrayList();
|
private final ObservableList<ClosedTradesListItem> list = FXCollections.observableArrayList();
|
||||||
private final ListChangeListener<Trade> tradesListChangeListener;
|
private final ListChangeListener<Tradable> tradesListChangeListener;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ClosedTradesDataModel(TradeManager tradeManager, User user) {
|
public ClosedTradesDataModel(ClosedTradableManager closedTradableManager) {
|
||||||
this.tradeManager = tradeManager;
|
this.closedTradableManager = closedTradableManager;
|
||||||
this.user = user;
|
|
||||||
|
|
||||||
tradesListChangeListener = change -> applyList();
|
tradesListChangeListener = change -> applyList();
|
||||||
}
|
}
|
||||||
|
@ -51,12 +48,12 @@ class ClosedTradesDataModel implements Activatable, DataModel {
|
||||||
@Override
|
@Override
|
||||||
public void activate() {
|
public void activate() {
|
||||||
applyList();
|
applyList();
|
||||||
tradeManager.getClosedTrades().addListener(tradesListChangeListener);
|
closedTradableManager.getClosedTrades().addListener(tradesListChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
tradeManager.getClosedTrades().removeListener(tradesListChangeListener);
|
closedTradableManager.getClosedTrades().removeListener(tradesListChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableList<ClosedTradesListItem> getList() {
|
public ObservableList<ClosedTradesListItem> getList() {
|
||||||
|
@ -64,16 +61,16 @@ class ClosedTradesDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Offer.Direction getDirection(Offer offer) {
|
public Offer.Direction getDirection(Offer offer) {
|
||||||
return tradeManager.isMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
return closedTradableManager.wasMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyList() {
|
private void applyList() {
|
||||||
list.clear();
|
list.clear();
|
||||||
|
|
||||||
list.addAll(tradeManager.getClosedTrades().stream().map(ClosedTradesListItem::new).collect(Collectors.toList()));
|
list.addAll(closedTradableManager.getClosedTrades().stream().map(ClosedTradesListItem::new).collect(Collectors.toList()));
|
||||||
|
|
||||||
// we sort by date, earliest first
|
// we sort by date, earliest first
|
||||||
list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate()));
|
list.sort((o1, o2) -> o2.getTradable().getDate().compareTo(o1.getTradable().getDate()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,22 +17,22 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.main.portfolio.closedtrades;
|
package io.bitsquare.gui.main.portfolio.closedtrades;
|
||||||
|
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Tradable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We could remove that wrapper if it is not needed for additional UI only fields.
|
* We could remove that wrapper if it is not needed for additional UI only fields.
|
||||||
*/
|
*/
|
||||||
class ClosedTradesListItem {
|
class ClosedTradesListItem {
|
||||||
|
|
||||||
private final Trade trade;
|
private final Tradable tradable;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ClosedTradesListItem(Trade trade) {
|
ClosedTradesListItem(Tradable tradable) {
|
||||||
this.trade = trade;
|
this.tradable = tradable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class ClosedTradesListItem {
|
||||||
// Getters
|
// Getters
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Trade getTrade() {
|
Tradable getTradable() {
|
||||||
return trade;
|
return tradable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,18 @@ package io.bitsquare.gui.main.portfolio.closedtrades;
|
||||||
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
|
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
|
||||||
import io.bitsquare.gui.common.model.ViewModel;
|
import io.bitsquare.gui.common.model.ViewModel;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.trade.states.OffererTradeState;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.states.TakerTradeState;
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
import io.bitsquare.trade.states.TradeState;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataModel> implements ViewModel {
|
class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataModel> implements ViewModel {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ClosedTradesViewModel.class);
|
||||||
|
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
|
|
||||||
|
@ -45,34 +48,39 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
|
||||||
}
|
}
|
||||||
|
|
||||||
String getTradeId(ClosedTradesListItem item) {
|
String getTradeId(ClosedTradesListItem item) {
|
||||||
return item.getTrade().getId();
|
return item.getTradable().getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
String getAmount(ClosedTradesListItem item) {
|
String getAmount(ClosedTradesListItem item) {
|
||||||
return (item != null) ? formatter.formatCoinWithCode(item.getTrade().getTradeAmount()) : "";
|
if (item != null && item.getTradable() instanceof Trade)
|
||||||
|
return formatter.formatCoinWithCode(((Trade) item.getTradable()).getTradeAmount());
|
||||||
|
else
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String getPrice(ClosedTradesListItem item) {
|
String getPrice(ClosedTradesListItem item) {
|
||||||
return (item != null) ? formatter.formatFiat(item.getTrade().getOffer().getPrice()) : "";
|
return (item != null) ? formatter.formatFiat(item.getTradable().getOffer().getPrice()) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String getVolume(ClosedTradesListItem item) {
|
String getVolume(ClosedTradesListItem item) {
|
||||||
return (item != null) ? formatter.formatFiatWithCode(item.getTrade().getTradeVolume()) : "";
|
if (item != null && item.getTradable() instanceof Trade)
|
||||||
|
return formatter.formatFiatWithCode(((Trade) item.getTradable()).getTradeVolume());
|
||||||
|
else
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String getDirectionLabel(ClosedTradesListItem item) {
|
String getDirectionLabel(ClosedTradesListItem item) {
|
||||||
return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getTrade().getOffer())) : "";
|
return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getTradable().getOffer())) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String getDate(ClosedTradesListItem item) {
|
String getDate(ClosedTradesListItem item) {
|
||||||
return formatter.formatDateTime(item.getTrade().getDate());
|
return formatter.formatDateTime(item.getTradable().getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
String getState(ClosedTradesListItem item) {
|
String getState(ClosedTradesListItem item) {
|
||||||
if (item != null && item.getTrade() != null) {
|
if (item != null) {
|
||||||
TradeState.LifeCycleState lifeCycleState = item.getTrade().lifeCycleStateProperty().get();
|
if (item.getTradable() instanceof Trade) {
|
||||||
if (lifeCycleState instanceof TakerTradeState.LifeCycleState) {
|
switch (((Trade) item.getTradable()).lifeCycleStateProperty().get()) {
|
||||||
switch ((TakerTradeState.LifeCycleState) lifeCycleState) {
|
|
||||||
case COMPLETED:
|
case COMPLETED:
|
||||||
return "Completed";
|
return "Completed";
|
||||||
case FAILED:
|
case FAILED:
|
||||||
|
@ -81,17 +89,22 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
|
||||||
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
|
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (lifeCycleState instanceof OffererTradeState.LifeCycleState) {
|
else if (item.getTradable() instanceof OpenOffer) {
|
||||||
switch ((OffererTradeState.LifeCycleState) lifeCycleState) {
|
OpenOffer.State state = ((OpenOffer) item.getTradable()).getState();
|
||||||
case OFFER_CANCELED:
|
log.trace("OpenOffer state {}", state);
|
||||||
|
switch (state) {
|
||||||
|
case AVAILABLE:
|
||||||
|
case RESERVED:
|
||||||
|
case CLOSED:
|
||||||
|
log.error("Invalid state {}", state);
|
||||||
|
return state.toString();
|
||||||
|
case CANCELED:
|
||||||
return "Canceled";
|
return "Canceled";
|
||||||
case COMPLETED:
|
/* case FAILED:
|
||||||
return "Completed";
|
return "Failed";*/
|
||||||
case FAILED:
|
default:
|
||||||
return "Failed";
|
log.error("Unhandled state {}", state);
|
||||||
case OFFER_OPEN:
|
return state.toString();
|
||||||
case PENDING:
|
|
||||||
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,21 +17,24 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.main.portfolio.openoffer;
|
package io.bitsquare.gui.main.portfolio.openoffer;
|
||||||
|
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We could remove that wrapper if it is not needed for additional UI only fields.
|
* We could remove that wrapper if it is not needed for additional UI only fields.
|
||||||
*/
|
*/
|
||||||
class OpenOfferListItem {
|
class OpenOfferListItem {
|
||||||
|
|
||||||
private final Offer offer;
|
private final OpenOffer openOffer;
|
||||||
|
|
||||||
public OpenOfferListItem(Trade trade) {
|
public OpenOfferListItem(OpenOffer openOffer) {
|
||||||
this.offer = trade.getOffer();
|
this.openOffer = openOffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OpenOffer getOpenOffer() {
|
||||||
|
return openOffer;
|
||||||
|
}
|
||||||
public Offer getOffer() {
|
public Offer getOffer() {
|
||||||
return offer;
|
return openOffer.getOffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,9 @@ import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.gui.common.model.Activatable;
|
import io.bitsquare.gui.common.model.Activatable;
|
||||||
import io.bitsquare.gui.common.model.DataModel;
|
import io.bitsquare.gui.common.model.DataModel;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
import io.bitsquare.user.User;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
@ -40,16 +39,14 @@ import org.slf4j.LoggerFactory;
|
||||||
class OpenOffersDataModel implements Activatable, DataModel {
|
class OpenOffersDataModel implements Activatable, DataModel {
|
||||||
private static final Logger log = LoggerFactory.getLogger(OpenOffersDataModel.class);
|
private static final Logger log = LoggerFactory.getLogger(OpenOffersDataModel.class);
|
||||||
|
|
||||||
private final TradeManager tradeManager;
|
private final OpenOfferManager openOfferManager;
|
||||||
private final User user;
|
|
||||||
|
|
||||||
private final ObservableList<OpenOfferListItem> list = FXCollections.observableArrayList();
|
private final ObservableList<OpenOfferListItem> list = FXCollections.observableArrayList();
|
||||||
private final ListChangeListener<Trade> tradesListChangeListener;
|
private final ListChangeListener<OpenOffer> tradesListChangeListener;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public OpenOffersDataModel(TradeManager tradeManager, User user) {
|
public OpenOffersDataModel(OpenOfferManager openOfferManager) {
|
||||||
this.tradeManager = tradeManager;
|
this.openOfferManager = openOfferManager;
|
||||||
this.user = user;
|
|
||||||
|
|
||||||
tradesListChangeListener = change -> applyList();
|
tradesListChangeListener = change -> applyList();
|
||||||
}
|
}
|
||||||
|
@ -57,16 +54,16 @@ class OpenOffersDataModel implements Activatable, DataModel {
|
||||||
@Override
|
@Override
|
||||||
public void activate() {
|
public void activate() {
|
||||||
applyList();
|
applyList();
|
||||||
tradeManager.getOpenOfferTrades().addListener(tradesListChangeListener);
|
openOfferManager.getOpenOffers().addListener(tradesListChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
tradeManager.getOpenOfferTrades().removeListener(tradesListChangeListener);
|
openOfferManager.getOpenOffers().removeListener(tradesListChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onCancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
void onCancelOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
tradeManager.onCancelOpenOffer(offer, resultHandler, errorMessageHandler);
|
openOfferManager.onCancelOpenOffer(openOffer, resultHandler, errorMessageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,13 +72,13 @@ class OpenOffersDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Offer.Direction getDirection(Offer offer) {
|
public Offer.Direction getDirection(Offer offer) {
|
||||||
return tradeManager.isMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
return openOfferManager.isMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyList() {
|
private void applyList() {
|
||||||
list.clear();
|
list.clear();
|
||||||
|
|
||||||
list.addAll(tradeManager.getOpenOfferTrades().stream().map(OpenOfferListItem::new).collect(Collectors.toList()));
|
list.addAll(openOfferManager.getOpenOffers().stream().map(OpenOfferListItem::new).collect(Collectors.toList()));
|
||||||
|
|
||||||
// we sort by date, earliest first
|
// we sort by date, earliest first
|
||||||
list.sort((o1, o2) -> o2.getOffer().getCreationDate().compareTo(o1.getOffer().getCreationDate()));
|
list.sort((o1, o2) -> o2.getOffer().getCreationDate().compareTo(o1.getOffer().getCreationDate()));
|
||||||
|
|
|
@ -25,7 +25,7 @@ import io.bitsquare.gui.main.MainView;
|
||||||
import io.bitsquare.gui.main.funds.FundsView;
|
import io.bitsquare.gui.main.funds.FundsView;
|
||||||
import io.bitsquare.gui.main.funds.withdrawal.WithdrawalView;
|
import io.bitsquare.gui.main.funds.withdrawal.WithdrawalView;
|
||||||
import io.bitsquare.gui.util.GUIUtil;
|
import io.bitsquare.gui.util.GUIUtil;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@ -69,8 +69,8 @@ public class OpenOffersView extends ActivatableViewAndModel<GridPane, OpenOffers
|
||||||
table.setItems(model.getList());
|
table.setItems(model.getList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCancelOpenOffer(Offer offer) {
|
private void onCancelOpenOffer(OpenOffer openOffer) {
|
||||||
model.onCancelOpenOffer(offer,
|
model.onCancelOpenOffer(openOffer,
|
||||||
() -> {
|
() -> {
|
||||||
log.debug("Remove offer was successful");
|
log.debug("Remove offer was successful");
|
||||||
Popups.openInfoPopup("You can withdraw the funds you paid in from the funds screens.");
|
Popups.openInfoPopup("You can withdraw the funds you paid in from the funds screens.");
|
||||||
|
@ -249,7 +249,7 @@ public class OpenOffersView extends ActivatableViewAndModel<GridPane, OpenOffers
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
button.setOnAction(event -> onCancelOpenOffer(item.getOffer()));
|
button.setOnAction(event -> onCancelOpenOffer(item.getOpenOffer()));
|
||||||
setGraphic(button);
|
setGraphic(button);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
|
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
|
||||||
import io.bitsquare.gui.common.model.ViewModel;
|
import io.bitsquare.gui.common.model.ViewModel;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
@ -45,8 +45,8 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void onCancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
void onCancelOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
dataModel.onCancelOpenOffer(offer, resultHandler, errorMessageHandler);
|
dataModel.onCancelOpenOffer(openOffer, resultHandler, errorMessageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableList<OpenOfferListItem> getList() {
|
public ObservableList<OpenOfferListItem> getList() {
|
||||||
|
|
|
@ -27,12 +27,12 @@ import io.bitsquare.gui.components.Popups;
|
||||||
import io.bitsquare.gui.main.MainView;
|
import io.bitsquare.gui.main.MainView;
|
||||||
import io.bitsquare.gui.main.portfolio.PortfolioView;
|
import io.bitsquare.gui.main.portfolio.PortfolioView;
|
||||||
import io.bitsquare.gui.main.portfolio.closedtrades.ClosedTradesView;
|
import io.bitsquare.gui.main.portfolio.closedtrades.ClosedTradesView;
|
||||||
import io.bitsquare.offer.Offer;
|
|
||||||
import io.bitsquare.trade.BuyerTrade;
|
import io.bitsquare.trade.BuyerTrade;
|
||||||
import io.bitsquare.trade.Contract;
|
import io.bitsquare.trade.Contract;
|
||||||
import io.bitsquare.trade.SellerTrade;
|
import io.bitsquare.trade.SellerTrade;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.states.TradeState;
|
import io.bitsquare.trade.states.TradeState;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.locale.Country;
|
import io.bitsquare.locale.Country;
|
||||||
import io.bitsquare.locale.CurrencyUtil;
|
import io.bitsquare.locale.CurrencyUtil;
|
||||||
import io.bitsquare.locale.LanguageUtil;
|
import io.bitsquare.locale.LanguageUtil;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue