Refactor buyer side tasks with task runner

This commit is contained in:
Manfred Karrer 2015-03-12 10:18:10 +01:00
parent ef4937bba1
commit 9c9064091a
49 changed files with 1456 additions and 1330 deletions

@ -183,7 +183,7 @@ class MainViewModel implements ViewModel {
Observable<Object> walletServiceObservable = walletService.initialize(Platform::runLater);
walletServiceObservable.subscribe(
next -> {
log.trace("wallet next");
//log.trace("wallet next");
},
error -> Platform.runLater(() -> {
log.trace("wallet error");
@ -195,7 +195,7 @@ class MainViewModel implements ViewModel {
Observable<UpdateProcess.State> updateProcessObservable = this.updateProcess.getProcess();
updateProcessObservable.subscribe(next -> {
log.trace("updateProcess next");
//log.trace("updateProcess next");
},
error -> {
log.trace("updateProcess error");

@ -163,6 +163,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
void fiatPaymentStarted() {
getTrade().setState(Trade.State.FIAT_PAYMENT_STARTED);
tradeManager.fiatPaymentStarted(getTrade().getId());
}

@ -148,7 +148,8 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
@FXML
void onShowPayFundsScreen() {
if (model.displaySecurityDepositInfo()) {
// TODO deactivate for testing the moment
/* if (model.displaySecurityDepositInfo()) {
overlayManager.blurContent();
List<Action> actions = new ArrayList<>();
actions.add(new AbstractAction(BSResources.get("shared.close")) {
@ -165,7 +166,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
actions);
model.securityDepositInfoDisplayed();
}
}*/
priceAmountPane.setInactive();

@ -138,7 +138,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
}
void takeOffer() {
final Trade trade = tradeManager.takeOffer(amountAsCoin.get(), offer);
final Trade trade = tradeManager.requestTakeOffer(amountAsCoin.get(), offer);
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue);
switch (newValue) {

@ -182,7 +182,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
@FXML
void onShowPayFundsScreen() {
if (model.displaySecurityDepositInfo()) {
// TODO deactivate for testing the moment
/* if (model.displaySecurityDepositInfo()) {
overlayManager.blurContent();
List<Action> actions = new ArrayList<>();
actions.add(new AbstractAction(BSResources.get("shared.close")) {
@ -198,7 +199,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
actions);
model.securityDepositInfoDisplayed();
}
}*/
priceAmountPane.setInactive();

@ -19,18 +19,36 @@ package io.bitsquare.offer;
import java.io.Serializable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OpenOffer implements Serializable {
public class OpenOffer implements Serializable {
private static final long serialVersionUID = -7523483764145982933L;
private static final Logger log = LoggerFactory.getLogger(OpenOffer.class);
private final Offer offer;
public OpenOffer( Offer offer) {
private static final Logger log = LoggerFactory.getLogger(OpenOffer.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public static enum State {
OPEN,
OFFER_ACCEPTED
}
private final Offer offer;
private State state;
transient private ObjectProperty<State> _state;
public OpenOffer(Offer offer) {
this.offer = offer;
state = State.OPEN;
}
public Offer getOffer() {
@ -40,4 +58,20 @@ public class OpenOffer implements Serializable {
public String getId() {
return offer.getId();
}
public void setState(State state) {
this.state = state;
stateProperty().set(state);
}
public State getState() {
return state;
}
public ObjectProperty<State> stateProperty() {
if (_state == null)
_state = new SimpleObjectProperty<>(state);
return _state;
}
}

@ -18,7 +18,6 @@
package io.bitsquare.trade;
import io.bitsquare.offer.Offer;
import io.bitsquare.util.tasks.Task;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
@ -33,24 +32,6 @@ import javafx.beans.property.SimpleObjectProperty;
public class Trade implements Serializable {
private static final long serialVersionUID = -8275323072940974077L;
private Class<? extends Task> previousTask;
private Class<? extends Task> currentTask;
public void setCurrentTask(Class<? extends Task> currentTask) {
this.currentTask = currentTask;
}
public Class<? extends Task> getCurrentTask() {
return currentTask;
}
public void setPreviousTask(Class<? extends Task> previousTask) {
this.previousTask = previousTask;
}
public Class<? extends Task> getPreviousTask() {
return previousTask;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Enum

@ -30,31 +30,21 @@ import io.bitsquare.offer.OfferBookService;
import io.bitsquare.offer.OpenOffer;
import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.handlers.TransactionResultHandler;
import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener;
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
import io.bitsquare.trade.protocol.trade.OfferMessage;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.TakerDepositPaymentRequestMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.IsOfferAvailableResponse;
import io.bitsquare.trade.protocol.trade.taker.RequestIsOfferAvailableProtocol;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
import io.bitsquare.user.User;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ResultHandler;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.utils.Fiat;
import java.util.HashMap;
@ -91,8 +81,8 @@ public class TradeManager {
private final OfferBookService offerBookService;
//TODO store TakerAsSellerProtocol in trade
private final Map<String, SellerTakesOfferProtocol> takerAsSellerProtocolMap = new HashMap<>();
private final Map<String, BuyerAcceptsOfferProtocol> offererAsBuyerProtocolMap = new HashMap<>();
private final Map<String, SellerAsTakerProtocol> takerAsSellerProtocolMap = new HashMap<>();
private final Map<String, BuyerAsOffererProtocol> offererAsBuyerProtocolMap = new HashMap<>();
private final Map<String, RequestIsOfferAvailableProtocol> requestIsOfferAvailableProtocolMap = new HashMap<>();
private final ObservableMap<String, OpenOffer> openOffers = FXCollections.observableHashMap();
@ -184,7 +174,7 @@ public class TradeManager {
walletService,
offerBookService,
(transaction) -> {
saveOpenOffer(new OpenOffer(offer));
createOpenOffer(offer);
resultHandler.handleResult(transaction);
},
(message, throwable) -> errorMessageHandler.handleErrorMessage(message)
@ -193,9 +183,12 @@ public class TradeManager {
placeOfferProtocol.placeOffer();
}
private void saveOpenOffer(OpenOffer openOffer) {
private void createOpenOffer(Offer offer) {
OpenOffer openOffer = new OpenOffer(offer);
openOffers.put(openOffer.getId(), openOffer);
persistOpenOffers();
createOffererAsBuyerProtocol(openOffer);
}
public void requestRemoveOpenOffer(String offerId, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
@ -261,137 +254,53 @@ public class TradeManager {
// Trading protocols
///////////////////////////////////////////////////////////////////////////////////////////
private void createOffererAsBuyerProtocol(String offerId, Peer sender) {
log.trace("createOffererAsBuyerProtocol offerId = " + offerId);
if (openOffers.containsKey(offerId)) {
Offer offer = openOffers.get(offerId).getOffer();
Trade trade = createTrade(offer);
private void createOffererAsBuyerProtocol(OpenOffer openOffer) {
BuyerAsOffererModel model = new BuyerAsOffererModel(
openOffer,
tradeMessageService,
walletService,
blockChainService,
signatureService,
user);
BuyerAcceptsOfferProtocol buyerAcceptsOfferProtocol = new BuyerAcceptsOfferProtocol(trade,
sender,
tradeMessageService,
walletService,
blockChainService,
signatureService,
user,
new BuyerAcceptsOfferProtocolListener() {
@Override
public void onOfferAccepted(Offer offer) {
persistPendingTrades();
//TODO do that later
/*requestRemoveOpenOffer(offer.getId(),
() -> log.debug("remove offer was successful"),
(message) -> log.error(message));*/
}
@Override
public void onDepositTxPublished(Transaction depositTx) {
persistPendingTrades();
}
// TODO should be removed
@Override
public void onDepositTxConfirmedInBlockchain() {
log.trace("trading onDepositTxConfirmedInBlockchain");
trade.setState(Trade.State.DEPOSIT_CONFIRMED);
persistPendingTrades();
}
@Override
public void onPayoutTxPublished(Transaction payoutTx) {
trade.setPayoutTx(payoutTx);
trade.setState(Trade.State.PAYOUT_PUBLISHED);
// We close the trade when the user has withdrawn his trade funds (see #283)
//closeTrade(trade);
log.debug("trading onPayoutTxPublishedMessage");
}
@Override
public void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state) {
log.error("Error while executing trade process at state: " + state + " / " + throwable);
switch (state) {
case RespondToTakeOfferRequest:
removeFailedTrade(trade);
break;
case ValidateTakeOfferFeePayedMessage:
removeFailedTrade(trade);
break;
case CreateDepositTx:
removeFailedTrade(trade);
break;
case SendTakerDepositPaymentRequest:
removeFailedTrade(trade);
break;
case ValidateRequestOffererPublishDepositTxMessage:
removeFailedTrade(trade);
break;
case VerifyTakerAccount:
removeFailedTrade(trade);
break;
case VerifyAndSignContract:
removeFailedTrade(trade);
break;
case SignAndPublishDepositTx:
removeFailedTrade(trade);
break;
case SignAndPublishDepositTxResulted:
removeFailedTrade(trade);
break;
case SendSignedPayoutTx:
removeFailedTrade(trade);
break;
default:
log.error("Unhandled state: " + state);
break;
}
}
});
if (!offererAsBuyerProtocolMap.containsKey(trade.getId())) {
offererAsBuyerProtocolMap.put(trade.getId(), buyerAcceptsOfferProtocol);
}
else {
// We don't store the protocol in case we have already an open offer. The protocol is only
// temporary used to reply with a reject message.
log.trace("offererAsBuyerProtocol not stored as offer is already pending.");
}
buyerAcceptsOfferProtocol.start();
}
else {
log.warn("Incoming offer take request does not match with any saved offer. We ignore that request.");
}
}
public Trade takeOffer(Coin amount, Offer offer) {
Trade trade = createTrade(offer);
trade.setTradeAmount(amount);
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
openOffer.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue);
switch (newValue) {
case OPEN:
break;
case OFFERER_ACCEPTED:
persistPendingTrades();
break;
case OFFERER_REJECTED:
removeFailedTrade(trade);
break;
case DEPOSIT_PUBLISHED:
persistPendingTrades();
break;
case DEPOSIT_CONFIRMED:
break;
case FIAT_PAYMENT_STARTED:
persistPendingTrades();
break;
case FAILED:
removeFailedTrade(trade);
break;
case PAYOUT_PUBLISHED:
case OFFER_ACCEPTED:
requestRemoveOpenOffer(openOffer.getId(),
() -> log.debug("remove offer was successful"),
(message) -> log.error(message));
Trade trade = model.getTrade();
pendingTrades.put(trade.getId(), trade);
persistPendingTrades();
currentPendingTrade = trade;
// TODO check, remove listener
trade.stateProperty().addListener((ov2, oldValue2, newValue2) -> {
log.debug("trade state = " + newValue);
switch (newValue2) {
case OPEN:
break;
case OFFERER_ACCEPTED: // only taker side
case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED:
case FIAT_PAYMENT_STARTED:
case FIAT_PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED:
persistPendingTrades();
break;
case OFFERER_REJECTED:
case FAILED:
removeFailedTrade(trade);
break;
default:
log.error("Unhandled trade state: " + newValue);
break;
}
});
break;
default:
log.error("Unhandled trade state: " + newValue);
@ -399,7 +308,41 @@ public class TradeManager {
}
});
SellerTakesOfferModel model = new SellerTakesOfferModel(
BuyerAsOffererProtocol buyerAcceptsOfferProtocol = new BuyerAsOffererProtocol(model);
offererAsBuyerProtocolMap.put(openOffer.getId(), buyerAcceptsOfferProtocol);
buyerAcceptsOfferProtocol.start();
}
public Trade requestTakeOffer(Coin amount, Offer offer) {
Trade trade = createTrade(offer);
trade.setTradeAmount(amount);
// TODO check
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue);
switch (newValue) {
case OPEN:
break;
case OFFERER_ACCEPTED:
case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED:
case FIAT_PAYMENT_STARTED:
case FIAT_PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED:
persistPendingTrades();
break;
case OFFERER_REJECTED:
case FAILED:
removeFailedTrade(trade);
break;
default:
log.error("Unhandled trade state: " + newValue);
break;
}
});
SellerAsTakerModel model = new SellerAsTakerModel(
trade,
tradeMessageService,
walletService,
@ -407,10 +350,10 @@ public class TradeManager {
signatureService,
user);
SellerTakesOfferProtocol sellerTakesOfferProtocol = new SellerTakesOfferProtocol(model);
SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model);
takerAsSellerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
sellerTakesOfferProtocol.start();
sellerTakesOfferProtocol.handleRequestTakeOfferUIEvent();
return trade;
}
@ -420,8 +363,7 @@ public class TradeManager {
// Also we don't support yet offline messaging (mail box)
public void fiatPaymentStarted(String tradeId) {
if (offererAsBuyerProtocolMap.get(tradeId) != null) {
offererAsBuyerProtocolMap.get(tradeId).handleUIEventBankTransferStarted();
pendingTrades.get(tradeId).setState(Trade.State.FIAT_PAYMENT_STARTED);
offererAsBuyerProtocolMap.get(tradeId).handleBankTransferStartedUIEvent();
persistPendingTrades();
}
else {
@ -464,6 +406,7 @@ public class TradeManager {
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName());
log.trace("handleNewMessage: sender = " + sender);
// TODO remove
if (message instanceof OfferMessage) {
OfferMessage offerMessage = (OfferMessage) message;
// Before starting any take offer activity we check if the offer is still available.
@ -491,40 +434,6 @@ public class TradeManager {
log.error("Incoming offerMessage not supported. " + offerMessage);
}
}
else if (message instanceof TradeMessage) {
TradeMessage tradeMessage = (TradeMessage) message;
String tradeId = tradeMessage.getTradeId();
checkNotNull(tradeId);
if (tradeMessage instanceof RequestTakeOfferMessage) {
// Step 3. in trade protocol
createOffererAsBuyerProtocol(tradeId, sender);
}
else if (tradeMessage instanceof RespondToTakeOfferRequestMessage) {
}
else if (tradeMessage instanceof TakeOfferFeePayedMessage) {
offererAsBuyerProtocolMap.get(tradeId).handleTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage);
}
else if (tradeMessage instanceof TakerDepositPaymentRequestMessage) {
}
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {
offererAsBuyerProtocolMap.get(tradeId).handleRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
}
else if (tradeMessage instanceof DepositTxPublishedMessage) {
// persistPendingTrades();
}
else if (tradeMessage instanceof BankTransferInitedMessage) {
}
else if (tradeMessage instanceof PayoutTxPublishedMessage) {
offererAsBuyerProtocolMap.get(tradeId).handlePayoutTxPublishedMessage((PayoutTxPublishedMessage) tradeMessage);
}
else {
log.error("Incoming tradeMessage not supported. " + tradeMessage);
}
}
else {
log.error("Incoming message not supported. " + message);
}
}

@ -1,29 +0,0 @@
/*
* 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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TradeState {
private static final Logger log = LoggerFactory.getLogger(TradeState.class);
public TradeState() {
}
}

@ -1,35 +0,0 @@
/*
* 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.listeners;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol;
import org.bitcoinj.core.Transaction;
public interface BuyerAcceptsOfferProtocolListener {
void onOfferAccepted(Offer offer);
void onDepositTxPublished(Transaction depositTx);
void onDepositTxConfirmedInBlockchain();
void onPayoutTxPublished(Transaction payoutTx);
void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state);
}

@ -17,22 +17,137 @@
package io.bitsquare.trade.protocol.trade;
import io.bitsquare.trade.Trade;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.user.User;
import io.bitsquare.util.tasks.SharedModel;
import org.bitcoinj.core.ECKey;
import java.security.PublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TradeSharedModel extends SharedModel {
private static final Logger log = LoggerFactory.getLogger(TradeSharedModel.class);
protected static final Logger log = LoggerFactory.getLogger(TradeSharedModel.class);
public Trade getTrade() {
return trade;
// provided
protected final Offer offer;
protected final TradeMessageService tradeMessageService;
protected final WalletService walletService;
protected final BlockChainService blockChainService;
protected final SignatureService signatureService;
// derived
protected final String arbitratorPubKey;
protected final BankAccount bankAccount;
protected final String accountId;
protected final PublicKey messagePublicKey;
protected final ECKey accountKey;
// data written/read by tasks
private TradeMessage tradeMessage;
protected String tradePubKeyAsHex;
protected String peersAccountId;
protected BankAccount peersBankAccount;
public TradeSharedModel(Offer offer,
TradeMessageService tradeMessageService,
WalletService walletService,
BlockChainService blockChainService,
SignatureService signatureService,
User user) {
this.offer = offer;
this.tradeMessageService = tradeMessageService;
this.walletService = walletService;
this.blockChainService = blockChainService;
this.signatureService = signatureService;
//TODO use default arbitrator for now
arbitratorPubKey = offer.getArbitrators().get(0).getPubKeyAsHex();
bankAccount = user.getBankAccount(offer.getBankAccountId());
accountId = user.getAccountId();
messagePublicKey = user.getMessagePublicKey();
accountKey = walletService.getRegistrationAddressEntry().getKey();
}
protected final Trade trade;
// getter/setter
public TradeSharedModel(Trade trade) {
this.trade = trade;
public TradeMessageService getTradeMessageService() {
return tradeMessageService;
}
public WalletService getWalletService() {
return walletService;
}
public BlockChainService getBlockChainService() {
return blockChainService;
}
public SignatureService getSignatureService() {
return signatureService;
}
public Offer getOffer() {
return offer;
}
public String getArbitratorPubKey() {
return arbitratorPubKey;
}
public BankAccount getBankAccount() {
return bankAccount;
}
public String getAccountId() {
return accountId;
}
public PublicKey getMessagePublicKey() {
return messagePublicKey;
}
public ECKey getAccountKey() {
return accountKey;
}
public String getTradePubKeyAsHex() {
return tradePubKeyAsHex;
}
public void setTradePubKeyAsHex(String tradePubKeyAsHex) {
this.tradePubKeyAsHex = tradePubKeyAsHex;
}
public String getPeersAccountId() {
return peersAccountId;
}
public void setPeersAccountId(String peersAccountId) {
this.peersAccountId = peersAccountId;
}
public BankAccount getPeersBankAccount() {
return peersBankAccount;
}
public void setPeersBankAccount(BankAccount peersBankAccount) {
this.peersBankAccount = peersBankAccount;
}
public TradeMessage getTradeMessage() {
return tradeMessage;
}
public void setTradeMessage(TradeMessage tradeMessage) {
this.tradeMessage = tradeMessage;
}
}

@ -1,465 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendTakerDepositPaymentRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils;
import java.security.PublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing
* from the peer.
* <p/>
* This class handles the role of the offerer as the Bitcoin buyer.
* <p/>
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages need to be validated before further processing.
*/
public class BuyerAcceptsOfferProtocol {
private static final Logger log = LoggerFactory.getLogger(BuyerAcceptsOfferProtocol.class);
public enum State {
Init,
RespondToTakeOfferRequest,
/* VerifyTakeOfferFeePayment,*/
ValidateTakeOfferFeePayedMessage,
CreateDepositTx,
SendTakerDepositPaymentRequest,
ValidateRequestOffererPublishDepositTxMessage,
VerifyTakerAccount,
VerifyAndSignContract,
SignAndPublishDepositTx,
SignAndPublishDepositTxResulted,
SignPayoutTx,
SendSignedPayoutTx
}
// provided
private final Trade trade;
private final Peer peer;
private final TradeMessageService tradeMessageService;
private final WalletService walletService;
private final BlockChainService blockChainService;
private final SignatureService signatureService;
private final BuyerAcceptsOfferProtocolListener listener;
// derived
private final String tradeId;
private final Offer offer;
private final String arbitratorPubKey;
private final BankAccount bankAccount;
private final String accountId;
private final PublicKey messagePublicKey;
private final ECKey accountKey;
private final String payoutAddress;
// data written/read by tasks
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
// data written by messages, read by tasks
private String takeOfferFeeTxId;
private String tradePubKeyAsHex;
private String peersPayoutAddress;
private String peersAccountId;
private BankAccount peersBankAccount;
private PublicKey peersMessagePublicKey;
private String peersContractAsJson;
private String signedTakerDepositTxAsHex;
private String txConnOutAsHex;
private String txScriptSigAsHex;
private long takerTxOutIndex;
// state
private State state;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public BuyerAcceptsOfferProtocol(Trade trade,
Peer peer,
TradeMessageService tradeMessageService,
WalletService walletService,
BlockChainService blockChainService,
SignatureService signatureService,
User user,
BuyerAcceptsOfferProtocolListener listener) {
this.trade = trade;
this.peer = peer;
this.listener = listener;
this.tradeMessageService = tradeMessageService;
this.walletService = walletService;
this.blockChainService = blockChainService;
this.signatureService = signatureService;
tradeId = trade.getId();
offer = trade.getOffer();
checkNotNull(tradeId);
checkNotNull(offer);
//TODO use default arbitrator for now
arbitratorPubKey = offer.getArbitrators().get(0).getPubKeyAsHex();
bankAccount = user.getBankAccount(trade.getOffer().getBankAccountId());
accountId = user.getAccountId();
messagePublicKey = user.getMessagePublicKey();
accountKey = walletService.getRegistrationAddressEntry().getKey();
payoutAddress = walletService.getAddressInfoByTradeID(tradeId).getAddressString();
state = State.Init;
}
public void start() {
respondToTakeOfferRequest();
}
// 4. RespondToTakeOfferRequest
private void respondToTakeOfferRequest() {
log.debug("respondToTakeOfferRequest called: state = " + state);
state = State.RespondToTakeOfferRequest;
RespondToTakeOfferRequest.run(this::handleRespondToTakeOfferRequestResult, this::handleErrorMessage, tradeMessageService, peer,
trade.getState(), tradeId);
}
private void handleRespondToTakeOfferRequestResult() {
log.debug("handleRespondToTakeOfferRequestResult called: state = " + state);
// Here we are not setting a state as that is not relevant for the trade process.
// In accept case we remove the offer from the offerbook, but that happens outside of the flow of the trade process
if (trade.getState() == Trade.State.OPEN) {
trade.setState(Trade.State.OFFERER_ACCEPTED);
listener.onOfferAccepted(offer);
}
else {
log.info("Ignore that request as we have already the offer accepted.");
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// 8. handleTakeOfferFeePayedMessage
public void handleTakeOfferFeePayedMessage(TakeOfferFeePayedMessage message) {
log.debug("handleTakeOfferFeePayedMessage called: state = " + state);
// validation
try {
checkState(state == State.RespondToTakeOfferRequest);
state = State.ValidateTakeOfferFeePayedMessage;
checkTradeId(tradeId, message);
String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
Coin tradeAmount = positiveCoinOf(nonZeroCoinOf(message.getTradeAmount()));
String tradePubKeyAsHex = nonEmptyStringOf(message.getTakerPubKeyAsHex());
// apply new state
this.takeOfferFeeTxId = takeOfferFeeTxId;
this.tradePubKeyAsHex = tradePubKeyAsHex;
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
trade.setTradeAmount(tradeAmount);
// next task
createDepositTx();
} catch (Throwable t) {
handleValidationFault(t);
}
}
// 9. CreateDepositTx
private void createDepositTx() {
log.debug("handleVerifyTakeOfferFeePaymentResult called: state = " + state);
state = State.CreateDepositTx;
CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, trade, tradePubKeyAsHex, arbitratorPubKey);
}
// 10. RequestTakerDepositPayment
private void handleCreateDepositTxResult(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex) {
log.debug("handleCreateDepositTxResult called: state = " + state);
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
this.offererTxOutIndex = offererTxOutIndex;
state = State.SendTakerDepositPaymentRequest;
SendTakerDepositPaymentRequest.run(this::handleErrorMessage,
peer,
tradeMessageService,
tradeId,
bankAccount,
accountId,
offererPubKey,
preparedOffererDepositTxAsHex,
offererTxOutIndex);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// 16. VerifyTakerAccount
public void handleRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message) {
log.debug("handleRequestOffererPublishDepositTxMessage called: state = " + state);
try {
// validation
checkState(state == State.SendTakerDepositPaymentRequest);
state = State.ValidateRequestOffererPublishDepositTxMessage;
checkTradeId(tradeId, message);
String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
PublicKey peersMessagePublicKey = checkNotNull(message.getTakerMessagePublicKey());
String peersContractAsJson = nonEmptyStringOf(message.getTakerContractAsJson());
String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// apply new state
this.peersPayoutAddress = peersPayoutAddress;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.peersMessagePublicKey = peersMessagePublicKey;
this.peersContractAsJson = peersContractAsJson;
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
this.txConnOutAsHex = txConnOutAsHex;
this.txScriptSigAsHex = txScriptSigAsHex;
this.takerTxOutIndex = takerTxOutIndex;
// next task
verifyTakerAccount();
} catch (Throwable t) {
handleValidationFault(t);
}
}
// 17. VerifyTakerAccount
private void verifyTakerAccount() {
state = State.VerifyTakerAccount;
VerifyTakerAccount.run(this::handleVerifyTakerAccountResult, this::handleFault, blockChainService,
this.peersAccountId, this.peersBankAccount);
}
// 18. VerifyAndSignContract
private void handleVerifyTakerAccountResult() {
log.debug("handleVerifyTakerAccountResult called: state = " + state);
Coin tradeAmount = trade.getTradeAmount();
state = State.VerifyAndSignContract;
VerifyAndSignContract.run(this::handleVerifyAndSignContractResult,
this::handleFault,
signatureService,
accountId,
tradeAmount,
takeOfferFeeTxId,
messagePublicKey,
offer,
peersAccountId,
bankAccount,
peersBankAccount,
peersMessagePublicKey,
peersContractAsJson,
accountKey);
}
// 19. SignAndPublishDepositTx
private void handleVerifyAndSignContractResult(Contract contract, String contractAsJson, String signature) {
log.debug("handleVerifyAndSignContractResult called: state = " + state);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setTakerContractSignature(signature);
state = State.SignAndPublishDepositTx;
SignAndPublishDepositTx.run(this::handleSignAndPublishDepositTxResult,
this::handleFault,
walletService,
preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex);
}
private void handleSignAndPublishDepositTxResult(Transaction depositTransaction) {
log.debug("handleSignAndPublishDepositTxResult called: state = " + state);
state = State.SignAndPublishDepositTxResulted;
trade.setDepositTx(depositTransaction);
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
listener.onDepositTxPublished(depositTransaction);
sendDepositTxIdToTaker(depositTransaction);
setupListenerForBlockChainConfirmation();
}
// 20a. SendDepositTxIdToTaker
private void sendDepositTxIdToTaker(Transaction depositTransaction) {
log.debug("sendDepositTxIdToTaker called: state = " + state);
SendDepositTxIdToTaker.run(this::handleErrorMessage, peer, tradeMessageService, tradeId, depositTransaction);
}
// TODO remove
// 20b. SetupListenerForBlockChainConfirmation
private void setupListenerForBlockChainConfirmation() {
log.debug("setupListenerForBlockChainConfirmation called: state = " + state);
SetupListenerForBlockChainConfirmation.run(trade.getDepositTx(), listener);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered from UI event: Button click "Bank transfer inited"
// 23. SignPayoutTx
public void handleUIEventBankTransferStarted() {
log.debug("handleUIEventBankTransferStarted called: state = " + state);
String depositTransactionId = trade.getDepositTx().getHashAsString();
Coin securityDeposit = trade.getSecurityDeposit();
Coin tradeAmount = trade.getTradeAmount();
state = State.SignPayoutTx;
SignPayoutTx.run(this::handleSignPayoutTxResult,
this::handleFault,
walletService,
tradeId,
peersPayoutAddress,
payoutAddress,
depositTransactionId,
securityDeposit,
tradeAmount);
}
// 24a. SendBankTransferInitedMessage
private void handleSignPayoutTxResult(String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
String offererPayoutAddress) {
log.debug("handleSignPayoutTxResult called: state = " + state);
state = State.SendSignedPayoutTx;
SendBankTransferInitedMessage.run(this::handleFault,
peer,
tradeMessageService,
tradeId,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
verifyTakeOfferFeePayment();
}
// 24b VerifyTakeOfferFeePayment
private void verifyTakeOfferFeePayment() {
VerifyTakeOfferFeePayment.run(this::handleFault, walletService, this.takeOfferFeeTxId);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// 28. handlePayoutTxPublishedMessage
public void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage message) {
log.debug("onPayoutTxPublishedMessage called: state = " + state);
try {
// validation
checkState(state == State.SendSignedPayoutTx);
checkTradeId(tradeId, message);
String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex());
// apply new state
Transaction payoutTx = new Transaction(walletService.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
listener.onPayoutTxPublished(payoutTx);
} catch (Throwable t) {
handleValidationFault(t);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void handleFault(Throwable throwable) {
trade.setFault(throwable);
trade.setState(Trade.State.FAILED);
listener.onFault(throwable, state);
}
private void handleErrorMessage(String errorMessage) {
handleFault(new Exception(errorMessage));
}
private void handleValidationFault(Throwable throwable) {
throwable.printStackTrace();
log.error(throwable.getMessage());
handleErrorMessage("Validation of incoming message failed. Error message = " + throwable.getMessage());
}
}

@ -0,0 +1,282 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.OpenOffer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.protocol.trade.TradeSharedModel;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import java.security.PublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BuyerAsOffererModel extends TradeSharedModel {
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class);
// provided
private final OpenOffer openOffer;
// derived
private final String offererPaybackAddress;
// data written/read by tasks
private Trade trade;
private Peer peer;
private String preparedOffererDepositTxAsHex;
private String depositTxAsHex;
private String peersAccountId;
private BankAccount peersBankAccount;
private PublicKey peersMessagePublicKey;
private String peersContractAsJson;
private String signedTakerDepositTxAsHex;
private String txConnOutAsHex;
private String txScriptSigAsHex;
private long takerTxOutIndex;
private Coin takerPaybackAmount;
private String takeOfferFeeTxId;
private String tradePubKeyAsHex;
private String takerPayoutAddress;
private long offererTxOutIndex;
private String offererPubKey;
private String offererSignatureR;
private String offererSignatureS;
private Coin offererPaybackAmount;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public BuyerAsOffererModel(OpenOffer openOffer,
TradeMessageService tradeMessageService,
WalletService walletService,
BlockChainService blockChainService,
SignatureService signatureService,
User user) {
super(openOffer.getOffer(),
tradeMessageService,
walletService,
blockChainService,
signatureService,
user);
this.openOffer = openOffer;
offererPaybackAddress = walletService.getAddressInfoByTradeID(offer.getId()).getAddressString();
}
//getter/setter
public OpenOffer getOpenOffer() {
return openOffer;
}
public Peer getPeer() {
return peer;
}
public String getOffererPaybackAddress() {
return offererPaybackAddress;
}
public String getPreparedOffererDepositTxAsHex() {
return preparedOffererDepositTxAsHex;
}
public void setPreparedOffererDepositTxAsHex(String preparedOffererDepositTxAsHex) {
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
}
public long getOffererTxOutIndex() {
return offererTxOutIndex;
}
public void setOffererTxOutIndex(long offererTxOutIndex) {
this.offererTxOutIndex = offererTxOutIndex;
}
public String getTakeOfferFeeTxId() {
return takeOfferFeeTxId;
}
public void setTakeOfferFeeTxId(String takeOfferFeeTxId) {
this.takeOfferFeeTxId = takeOfferFeeTxId;
}
@Override
public String getTradePubKeyAsHex() {
return tradePubKeyAsHex;
}
@Override
public void setTradePubKeyAsHex(String tradePubKeyAsHex) {
this.tradePubKeyAsHex = tradePubKeyAsHex;
}
public String getTakerPayoutAddress() {
return takerPayoutAddress;
}
public void setTakerPayoutAddress(String takerPayoutAddress) {
this.takerPayoutAddress = takerPayoutAddress;
}
@Override
public String getPeersAccountId() {
return peersAccountId;
}
@Override
public void setPeersAccountId(String peersAccountId) {
this.peersAccountId = peersAccountId;
}
@Override
public BankAccount getPeersBankAccount() {
return peersBankAccount;
}
@Override
public void setPeersBankAccount(BankAccount peersBankAccount) {
this.peersBankAccount = peersBankAccount;
}
public PublicKey getPeersMessagePublicKey() {
return peersMessagePublicKey;
}
public void setPeersMessagePublicKey(PublicKey peersMessagePublicKey) {
this.peersMessagePublicKey = peersMessagePublicKey;
}
public String getPeersContractAsJson() {
return peersContractAsJson;
}
public void setPeersContractAsJson(String peersContractAsJson) {
this.peersContractAsJson = peersContractAsJson;
}
public String getSignedTakerDepositTxAsHex() {
return signedTakerDepositTxAsHex;
}
public void setSignedTakerDepositTxAsHex(String signedTakerDepositTxAsHex) {
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
}
public String getTxConnOutAsHex() {
return txConnOutAsHex;
}
public void setTxConnOutAsHex(String txConnOutAsHex) {
this.txConnOutAsHex = txConnOutAsHex;
}
public String getTxScriptSigAsHex() {
return txScriptSigAsHex;
}
public void setTxScriptSigAsHex(String txScriptSigAsHex) {
this.txScriptSigAsHex = txScriptSigAsHex;
}
public long getTakerTxOutIndex() {
return takerTxOutIndex;
}
public void setTakerTxOutIndex(long takerTxOutIndex) {
this.takerTxOutIndex = takerTxOutIndex;
}
public String getOffererPubKey() {
return offererPubKey;
}
public void setOffererPubKey(String offererPubKey) {
this.offererPubKey = offererPubKey;
}
public String getDepositTxAsHex() {
return depositTxAsHex;
}
public void setDepositTxAsHex(String depositTxAsHex) {
this.depositTxAsHex = depositTxAsHex;
}
public String getOffererSignatureR() {
return offererSignatureR;
}
public void setOffererSignatureR(String offererSignatureR) {
this.offererSignatureR = offererSignatureR;
}
public String getOffererSignatureS() {
return offererSignatureS;
}
public void setOffererSignatureS(String offererSignatureS) {
this.offererSignatureS = offererSignatureS;
}
public Coin getOffererPaybackAmount() {
return offererPaybackAmount;
}
public void setOffererPaybackAmount(Coin offererPaybackAmount) {
this.offererPaybackAmount = offererPaybackAmount;
}
public Coin getTakerPaybackAmount() {
return takerPaybackAmount;
}
public void setTakerPaybackAmount(Coin takerPaybackAmount) {
this.takerPaybackAmount = takerPaybackAmount;
}
public void setTrade(Trade trade) {
this.trade = trade;
}
public Trade getTrade() {
return trade;
}
public void setPeer(Peer peer) {
this.peer = peer;
}
}

@ -0,0 +1,218 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer;
import io.bitsquare.network.Message;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestTakeOfferMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessTakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendTakerDepositPaymentRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing
* from the peer.
* <p/>
* This class handles the role of the offerer as the Bitcoin buyer.
* <p/>
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages need to be validated before further processing.
*/
public class BuyerAsOffererProtocol {
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererProtocol.class);
private BuyerAsOffererModel model;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public BuyerAsOffererProtocol(BuyerAsOffererModel model) {
this.model = model;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
public void start() {
model.getTradeMessageService().addMessageHandler(this::handleMessage);
}
public void cleanup() {
model.getTradeMessageService().removeMessageHandler(this::handleMessage);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
private void handleMessage(Message message, Peer peer) {
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName());
if (message instanceof TradeMessage) {
TradeMessage tradeMessage = (TradeMessage) message;
nonEmptyStringOf(tradeMessage.getTradeId());
if (tradeMessage instanceof RequestTakeOfferMessage) {
handleRequestTakeOfferMessage((RequestTakeOfferMessage) tradeMessage, peer);
}
else if (tradeMessage instanceof TakeOfferFeePayedMessage) {
handleTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage);
}
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {
handleRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
}
else if (tradeMessage instanceof PayoutTxPublishedMessage) {
handlePayoutTxPublishedMessage((PayoutTxPublishedMessage) tradeMessage);
}
else {
log.error("Incoming tradeMessage not supported. " + tradeMessage);
}
}
}
private void handleRequestTakeOfferMessage(RequestTakeOfferMessage tradeMessage, Peer peer) {
model.setTradeMessage(tradeMessage);
model.setPeer(peer);
BuyerAsOffererTaskRunner<BuyerAsOffererModel> sequence = new BuyerAsOffererTaskRunner<>(model,
() -> {
log.debug("sequence0 completed");
},
(message, throwable) -> {
log.error(message);
}
);
sequence.addTasks(
ProcessRequestTakeOfferMessage.class,
RespondToTakeOfferRequest.class
);
sequence.run();
}
private void handleTakeOfferFeePayedMessage(TakeOfferFeePayedMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
BuyerAsOffererTaskRunner<BuyerAsOffererModel> sequence = new BuyerAsOffererTaskRunner<>(model,
() -> {
log.debug("sequence1 completed");
},
(message, throwable) -> {
log.error(message);
}
);
sequence.addTasks(
ProcessTakeOfferFeePayedMessage.class,
CreateDepositTx.class,
SendTakerDepositPaymentRequest.class
);
sequence.run();
}
private void handleRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
BuyerAsOffererTaskRunner<BuyerAsOffererModel> sequence = new BuyerAsOffererTaskRunner<>(model,
() -> {
log.debug("sequence2 completed");
},
(message, throwable) -> {
log.error(message);
}
);
sequence.addTasks(
ProcessRequestOffererPublishDepositTxMessage.class,
VerifyTakerAccount.class,
VerifyAndSignContract.class,
SignAndPublishDepositTx.class,
SetupListenerForBlockChainConfirmation.class,
SendDepositTxIdToTaker.class
);
sequence.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// UI event handling
///////////////////////////////////////////////////////////////////////////////////////////
// User clicked the "bank transfer started" button
public void handleBankTransferStartedUIEvent() {
BuyerAsOffererTaskRunner<BuyerAsOffererModel> sequence = new BuyerAsOffererTaskRunner<>(model,
() -> {
log.debug("sequence3 completed");
},
(message, throwable) -> {
log.error(message);
}
);
sequence.addTasks(
SignPayoutTx.class,
VerifyTakeOfferFeePayment.class,
SendBankTransferInitedMessage.class
);
sequence.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
private void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
BuyerAsOffererTaskRunner<BuyerAsOffererModel> sequence = new BuyerAsOffererTaskRunner<>(model,
() -> {
log.debug("sequence4 completed");
},
(message, throwable) -> {
log.error(message);
}
);
sequence.addTasks(ProcessPayoutTxPublishedMessage.class);
sequence.run();
}
}

@ -15,12 +15,11 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade;
package io.bitsquare.trade.protocol.trade.offerer;
import io.bitsquare.trade.protocol.trade.TradeSharedModel;
import io.bitsquare.trade.Trade;
import io.bitsquare.util.handlers.FaultHandler;
import io.bitsquare.util.handlers.ResultHandler;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.jetbrains.annotations.NotNull;
@ -28,26 +27,13 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TradeTaskRunner<T extends TradeSharedModel> extends TaskRunner<TradeSharedModel> {
private static final Logger log = LoggerFactory.getLogger(TradeTaskRunner.class);
public class BuyerAsOffererTaskRunner<T extends BuyerAsOffererModel> extends TaskRunner<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererTaskRunner.class);
public TradeTaskRunner(T sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
public BuyerAsOffererTaskRunner(T sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
super(sharedModel, resultHandler, faultHandler);
}
@Override
protected void setCurrentTask(Class<? extends Task> task) {
super.setCurrentTask(task);
sharedModel.getTrade().setCurrentTask(task);
}
@Override
protected void setPreviousTask(Class<? extends Task> task) {
super.setPreviousTask(task);
if (task != null)
sharedModel.getTrade().setPreviousTask(task);
}
@Override
public void handleFault(String message, @NotNull Throwable throwable) {
sharedModel.getTrade().setState(Trade.State.FAILED);

@ -18,9 +18,9 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService;
import io.bitsquare.trade.Trade;
import io.bitsquare.util.handlers.ExceptionHandler;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
@ -30,34 +30,35 @@ import org.bitcoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateDepositTx {
public class CreateDepositTx extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(CreateDepositTx.class);
public static void run(ResultHandler resultHandler,
ExceptionHandler exceptionHandler,
WalletService walletService,
Trade trade,
String takerMultiSigPubKey,
String arbitratorPubKeyAsHex) {
log.trace("Run CreateDepositTx task");
public CreateDepositTx(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
String offererPubKey = walletService.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
Transaction transaction = walletService.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerMultiSigPubKey,
arbitratorPubKeyAsHex, trade.getId());
String offererPubKey = model.getWalletService().getAddressInfoByTradeID(model.getTrade().getId()).getPubKeyAsHexString();
Coin offererInputAmount = model.getTrade().getSecurityDeposit().add(FeePolicy.TX_FEE);
Transaction transaction = model.getWalletService().offererCreatesMSTxAndAddPayment(
offererInputAmount,
offererPubKey,
model.getTradePubKeyAsHex(),
model.getArbitratorPubKey(),
model.getTrade().getId());
String preparedOffererDepositTxAsHex = Utils.HEX.encode(transaction.bitcoinSerialize());
long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex();
resultHandler.onResult(offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
model.setOffererPubKey(offererPubKey);
model.setPreparedOffererDepositTxAsHex(preparedOffererDepositTxAsHex);
model.setOffererTxOutIndex(offererTxOutIndex);
complete();
} catch (InsufficientMoneyException e) {
log.error("Create deposit tx failed due InsufficientMoneyException " + e);
exceptionHandler.handleException(e);
failed(e);
}
}
public interface ResultHandler {
void onResult(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex);
}
}

@ -0,0 +1,56 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.*;
public class ProcessPayoutTxPublishedMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessPayoutTxPublishedMessage.class);
public ProcessPayoutTxPublishedMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
String payoutTxAsHex = nonEmptyStringOf(((PayoutTxPublishedMessage) model.getTradeMessage()).getPayoutTxAsHex());
Transaction payoutTx = new Transaction(model.getWalletService().getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
model.getTrade().setPayoutTx(payoutTx);
model.getTrade().setState(Trade.State.PAYOUT_PUBLISHED);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

@ -0,0 +1,59 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestOffererPublishDepositTxMessage.class);
public ProcessRequestOffererPublishDepositTxMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
RequestOffererPublishDepositTxMessage message = (RequestOffererPublishDepositTxMessage) model.getTradeMessage();
model.setTakerPayoutAddress(nonEmptyStringOf(message.getTakerPayoutAddress()));
model.setPeersAccountId(nonEmptyStringOf(message.getTakerAccountId()));
model.setPeersBankAccount(checkNotNull(message.getTakerBankAccount()));
model.setPeersMessagePublicKey(checkNotNull(message.getTakerMessagePublicKey()));
model.setPeersContractAsJson(nonEmptyStringOf(message.getTakerContractAsJson()));
model.setSignedTakerDepositTxAsHex(nonEmptyStringOf(message.getSignedTakerDepositTxAsHex()));
model.setTxConnOutAsHex(nonEmptyStringOf(message.getTxConnOutAsHex()));
model.setTxScriptSigAsHex(nonEmptyStringOf(message.getTxScriptSigAsHex()));
model.setTakerTxOutIndex(nonNegativeLongOf(message.getTakerTxOutIndex()));
complete();
} catch (Throwable t) {
failed(t);
}
}
}

@ -0,0 +1,46 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessRequestTakeOfferMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestTakeOfferMessage.class);
public ProcessRequestTakeOfferMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkTradeId(model.getOffer().getId(), model.getTradeMessage());
complete();
} catch (Throwable t) {
failed(t);
}
}
}

@ -0,0 +1,55 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.*;
public class ProcessTakeOfferFeePayedMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessTakeOfferFeePayedMessage.class);
public ProcessTakeOfferFeePayedMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
Trade trade = model.getTrade();
TakeOfferFeePayedMessage takeOfferFeePayedMessage = (TakeOfferFeePayedMessage) model.getTradeMessage();
trade.setTakeOfferFeeTxID(nonEmptyStringOf(takeOfferFeePayedMessage.getTakeOfferFeeTxId()));
trade.setTradeAmount(positiveCoinOf(nonZeroCoinOf(takeOfferFeePayedMessage.getTradeAmount())));
model.setTakeOfferFeeTxId(nonEmptyStringOf(takeOfferFeePayedMessage.getTakeOfferFeeTxId()));
model.setTradePubKeyAsHex(nonEmptyStringOf(takeOfferFeePayedMessage.getTakerPubKeyAsHex()));
complete();
} catch (Throwable t) {
failed(t);
}
}
}

@ -17,43 +17,47 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.OpenOffer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RespondToTakeOfferRequest {
public class RespondToTakeOfferRequest extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(RespondToTakeOfferRequest.class);
public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler,
TradeMessageService tradeMessageService, Peer peer, Trade.State tradeState, String tradeId) {
log.trace("Run HandleTakeOfferRequest task");
boolean takeOfferRequestAccepted = tradeState == Trade.State.OPEN;
if (!takeOfferRequestAccepted) {
log.warn("Received take offer request but the offer not marked as open anymore.");
}
RespondToTakeOfferRequestMessage tradeMessage = new RespondToTakeOfferRequestMessage(tradeId, takeOfferRequestAccepted);
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
public RespondToTakeOfferRequest(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
boolean takeOfferRequestAccepted = model.getOpenOffer().getState() == OpenOffer.State.OPEN;
if (!takeOfferRequestAccepted)
log.info("Received take offer request but the offer not marked as open anymore.");
Trade trade = new Trade(model.getOpenOffer().getOffer());
model.setTrade(trade);
model.getOpenOffer().setState(OpenOffer.State.OFFER_ACCEPTED);
RespondToTakeOfferRequestMessage tradeMessage = new RespondToTakeOfferRequestMessage(trade.getId(), takeOfferRequestAccepted);
model.getTradeMessageService().sendMessage(model.getPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("RespondToTakeOfferRequestMessage successfully arrived at peer");
resultHandler.handleResult();
complete();
}
@Override
public void handleFault() {
log.error("AcceptTakeOfferRequestMessage did not arrive at peer");
errorMessageHandler.handleErrorMessage("AcceptTakeOfferRequestMessage did not arrive at peer");
failed("AcceptTakeOfferRequestMessage did not arrive at peer");
}
});
}
public interface ResultHandler {
void handleResult();
}
}

@ -17,53 +17,43 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
import io.bitsquare.util.handlers.ExceptionHandler;
import org.bitcoinj.core.Coin;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendBankTransferInitedMessage {
public class SendBankTransferInitedMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(SendBankTransferInitedMessage.class);
public static void run(ExceptionHandler exceptionHandler,
Peer peer,
TradeMessageService tradeMessageService,
String tradeId,
String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
String offererPayoutAddress) {
log.trace("Run SendSignedPayoutTx task");
try {
BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(tradeId,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("Sending BankTransferInitedMessage succeeded.");
}
public SendBankTransferInitedMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
public void handleFault() {
exceptionHandler.handleException(new Exception("Sending BankTransferInitedMessage failed."));
@Override
protected void run() {
BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(
model.getTrade().getId(),
model.getDepositTxAsHex(),
model.getOffererSignatureR(),
model.getOffererSignatureS(),
model.getOffererPaybackAmount(),
model.getTakerPaybackAmount(),
model.getOffererPaybackAddress());
model.getTradeMessageService().sendMessage(model.getPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("Sending BankTransferInitedMessage succeeded.");
complete();
}
}
});
} catch (Exception e) {
exceptionHandler.handleException(e);
}
@Override
public void handleFault() {
failed("Sending BankTransferInitedMessage failed.");
}
});
}
}

@ -17,39 +17,40 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendDepositTxIdToTaker {
public class SendDepositTxIdToTaker extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(SendDepositTxIdToTaker.class);
public static void run( ErrorMessageHandler errorMessageHandler, Peer peer,
TradeMessageService tradeMessageService, String tradeId, Transaction depositTransaction) {
log.trace("Run task");
DepositTxPublishedMessage tradeMessage =
new DepositTxPublishedMessage(tradeId, Utils.HEX.encode(depositTransaction.bitcoinSerialize()));
public SendDepositTxIdToTaker(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
@Override
protected void run() {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(model.getTrade().getId(),
Utils.HEX.encode(model.getTrade().getDepositTx().bitcoinSerialize()));
model.getTradeMessageService().sendMessage(model.getPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("DepositTxPublishedMessage successfully arrived at peer");
complete();
}
@Override
public void handleFault() {
log.error("DepositTxPublishedMessage did not arrive at peer");
errorMessageHandler.handleErrorMessage("DepositTxPublishedMessage did not arrive at peer");
failed("Sending DepositTxPublishedMessage failed.");
}
});
}
}

@ -17,43 +17,43 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.messages.TakerDepositPaymentRequestMessage;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendTakerDepositPaymentRequest {
public class SendTakerDepositPaymentRequest extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(SendTakerDepositPaymentRequest.class);
public static void run(ErrorMessageHandler errorMessageHandler,
Peer peer,
TradeMessageService tradeMessageService,
String tradeId,
BankAccount bankAccount,
String accountId,
String offererPubKey,
String preparedOffererDepositTxAsHex,
long offererTxOutIndex) {
log.trace("Run SendTakerDepositPaymentRequest task");
public SendTakerDepositPaymentRequest(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
TakerDepositPaymentRequestMessage tradeMessage = new TakerDepositPaymentRequestMessage(
tradeId, bankAccount, accountId, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
model.getTrade().getId(),
model.getBankAccount(),
model.getAccountId(),
model.getOffererPubKey(),
model.getPreparedOffererDepositTxAsHex(),
model.getOffererTxOutIndex());
model.getTradeMessageService().sendMessage(model.getPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
complete();
}
@Override
public void handleFault() {
log.error("RequestTakerDepositPaymentMessage did not arrive at peer");
errorMessageHandler.handleErrorMessage("RequestTakerDepositPaymentMessage did not arrive at peer");
failed("RequestTakerDepositPaymentMessage did not arrive at peer");
}
});
}
}

@ -17,7 +17,10 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
@ -26,25 +29,30 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// TODO should be removed
public class SetupListenerForBlockChainConfirmation {
public class SetupListenerForBlockChainConfirmation extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
public static void run(Transaction depositTransaction, BuyerAcceptsOfferProtocolListener listener) {
log.trace("Run SetupListenerForBlockChainConfirmation task");
//TODO
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
public SetupListenerForBlockChainConfirmation(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
depositTransaction.getConfidence().addEventListener(new TransactionConfidence.Listener() {
@Override
protected void run() {
TransactionConfidence confidence = model.getTrade().getDepositTx().getConfidence();
confidence.addEventListener(new TransactionConfidence.Listener() {
@Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason) {
log.trace("onConfidenceChanged " + tx.getConfidence());
if (reason == ChangeReason.TYPE &&
tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
listener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().removeEventListener(this);
log.trace("Tx is in blockchain");
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
model.getTrade().setState(Trade.State.DEPOSIT_CONFIRMED);
//TODO not sure if that works
confidence.removeEventListener(this);
}
}
});
complete();
}
}

@ -17,8 +17,10 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService;
import io.bitsquare.util.handlers.ExceptionHandler;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.bitcoinj.core.Transaction;
@ -29,47 +31,40 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishDepositTx {
public class SignAndPublishDepositTx extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
public static void run(ResultHandler resultHandler,
ExceptionHandler exceptionHandler,
WalletService walletService,
String preparedOffererDepositTxAsHex,
String signedTakerDepositTxAsHex,
String txConnOutAsHex,
String txScriptSigAsHex,
long offererTxOutIndex,
long takerTxOutIndex) {
log.trace("Run task");
public SignAndPublishDepositTx(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
walletService.offererSignAndPublishTx(preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex,
model.getWalletService().offererSignAndPublishTx(model.getPreparedOffererDepositTxAsHex(),
model.getSignedTakerDepositTxAsHex(),
model.getTxConnOutAsHex(),
model.getTxScriptSigAsHex(),
model.getOffererTxOutIndex(),
model.getTakerTxOutIndex(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("offererSignAndPublishTx succeeded " + transaction);
resultHandler.onResult(transaction);
model.getTrade().setDepositTx(transaction);
model.getTrade().setState(Trade.State.DEPOSIT_PUBLISHED);
complete();
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error("offererSignAndPublishTx faultHandler.onFault:" + t);
exceptionHandler.handleException(t);
failed(t);
}
});
} catch (Exception e) {
log.error("offererSignAndPublishTx faultHandler.onFault:" + e);
exceptionHandler.handleException(e);
failed(e);
}
}
public interface ResultHandler {
void onResult(Transaction depositTransaction);
}
}

@ -17,8 +17,10 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService;
import io.bitsquare.util.handlers.ExceptionHandler;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
@ -28,45 +30,37 @@ import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignPayoutTx {
public class SignPayoutTx extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(SignPayoutTx.class);
public static void run(ResultHandler resultHandler,
ExceptionHandler exceptionHandler,
WalletService walletService,
String tradeId,
String takerPayoutAddress,
String offererPayoutAddress,
String depositTransactionId,
Coin securityDeposit,
Coin tradeAmount) {
log.trace("Run SignPayoutTx task");
public SignPayoutTx(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
Coin offererPaybackAmount = tradeAmount.add(securityDeposit);
Trade trade = model.getTrade();
Coin securityDeposit = trade.getSecurityDeposit();
Coin offererPaybackAmount = trade.getTradeAmount().add(securityDeposit);
@SuppressWarnings("UnnecessaryLocalVariable") Coin takerPaybackAmount = securityDeposit;
Pair<ECKey.ECDSASignature, String> result = walletService.offererCreatesAndSignsPayoutTx(
depositTransactionId, offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, tradeId);
Pair<ECKey.ECDSASignature, String> result = model.getWalletService().offererCreatesAndSignsPayoutTx(
trade.getDepositTx().getHashAsString(), offererPaybackAmount, takerPaybackAmount, model.getTakerPayoutAddress(), model.getTrade().getId());
ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString();
String offererSignatureS = offererSignature.s.toString();
String depositTxAsHex = result.getValue();
resultHandler.handleResult(depositTxAsHex, offererSignatureR, offererSignatureS, offererPaybackAmount, takerPaybackAmount, offererPayoutAddress);
model.setDepositTxAsHex(depositTxAsHex);
model.setOffererSignatureR(offererSignature.r.toString());
model.setOffererSignatureS(offererSignature.s.toString());
model.setOffererPaybackAmount(offererPaybackAmount);
model.setTakerPaybackAmount(takerPaybackAmount);
complete();
} catch (Exception e) {
exceptionHandler.handleException(e);
failed(e);
}
}
public interface ResultHandler {
void handleResult(String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
String offererPayoutAddress);
}
}

@ -17,51 +17,44 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.Utilities;
import io.bitsquare.util.handlers.ExceptionHandler;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import java.security.PublicKey;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyAndSignContract {
public class VerifyAndSignContract extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class);
public static void run(ResultHandler resultHandler,
ExceptionHandler exceptionHandler,
SignatureService signatureService,
String accountId,
Coin tradeAmount,
String takeOfferFeeTxId,
PublicKey messagePublicKey,
Offer offer,
String peersAccountId,
BankAccount bankAccount,
BankAccount peersBankAccount,
PublicKey takerMessagePublicKey,
String peersContractAsJson,
ECKey registrationKey) {
log.trace("Run task");
Contract contract = new Contract(offer, tradeAmount, takeOfferFeeTxId, accountId, peersAccountId,
bankAccount, peersBankAccount, messagePublicKey, takerMessagePublicKey);
String contractAsJson = Utilities.objectToJson(contract);
log.trace("The 2 contracts as json does match");
String signature = signatureService.signMessage(registrationKey, contractAsJson);
//log.trace("signature: " + signature);
resultHandler.onResult(contract, contractAsJson, signature);
public VerifyAndSignContract(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
public interface ResultHandler {
void onResult(Contract contract, String contractAsJson, String signature);
@Override
protected void run() {
Trade trade = model.getTrade();
Contract contract = new Contract(
model.getOffer(),
trade.getTradeAmount(),
model.getTakeOfferFeeTxId(),
model.getAccountId(),
model.getPeersAccountId(),
model.getBankAccount(),
model.getPeersBankAccount(),
model.getMessagePublicKey(),
model.getPeersMessagePublicKey());
String contractAsJson = Utilities.objectToJson(contract);
String signature = model.getSignatureService().signMessage(model.getAccountKey(), contractAsJson);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setTakerContractSignature(signature);
complete();
}
}

@ -17,23 +17,29 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService;
import io.bitsquare.util.handlers.ExceptionHandler;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyTakeOfferFeePayment {
public class VerifyTakeOfferFeePayment extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(VerifyTakeOfferFeePayment.class);
public static void run(ExceptionHandler exceptionHandler, WalletService walletService,
String takeOfferFeeTxId) {
log.trace("Run VerifyTakeOfferFeePayment task");
public VerifyTakeOfferFeePayment(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
//TODO mocked yet, need a confidence listeners
int numOfPeersSeenTx = walletService.getNumOfPeersSeenTx(takeOfferFeeTxId);
int numOfPeersSeenTx = model.getWalletService().getNumOfPeersSeenTx(model.getTakeOfferFeeTxId());
/* if (numOfPeersSeenTx > 2) {
resultHandler.handleResult();
}*/
complete();
}
}

@ -17,22 +17,34 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.trade.protocol.trade.shared.tasks.VerifyPeerAccount;
import io.bitsquare.util.handlers.ExceptionHandler;
import io.bitsquare.util.handlers.ResultHandler;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyTakerAccount {
public class VerifyTakerAccount extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class);
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler,
BlockChainService blockChainService, String peersAccountId, BankAccount peersBankAccount) {
log.trace("Run task");
VerifyPeerAccount.run(resultHandler, exceptionHandler, blockChainService, peersAccountId, peersBankAccount);
public VerifyTakerAccount(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
//TODO mocked yet
if (model.getBlockChainService().verifyAccountRegistration()) {
if (model.getBlockChainService().isAccountBlackListed(model.getPeersAccountId(), model.getPeersBankAccount())) {
log.error("Taker is blacklisted");
failed("Taker is blacklisted");
}
else {
complete();
}
}
else {
failed("Account registration validation for peer failed.");
}
}
}

@ -17,20 +17,16 @@
package io.bitsquare.trade.protocol.trade.taker;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.TradeSharedModel;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Transaction;
import java.security.PublicKey;
@ -38,304 +34,175 @@ import java.security.PublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SellerTakesOfferModel extends TradeSharedModel {
private static final Logger log = LoggerFactory.getLogger(SellerTakesOfferModel.class);
private Transaction payoutTx;
private String payoutTxAsHex;
public class SellerAsTakerModel extends TradeSharedModel {
private static final Logger log = LoggerFactory.getLogger(SellerAsTakerModel.class);
public void setPayoutTx(Transaction payoutTx) {
this.payoutTx = payoutTx;
}
public Transaction getPayoutTx() {
return payoutTx;
}
public void setPayoutTxAsHex(String payoutTxAsHex) {
this.payoutTxAsHex = payoutTxAsHex;
}
public String getPayoutTxAsHex() {
return payoutTxAsHex;
}
public enum State {
Init,
GetPeerAddress,
RequestTakeOffer,
ValidateRespondToTakeOfferRequestMessage,
PayTakeOfferFee,
SendTakeOfferFeePayedMessage,
ValidateTakerDepositPaymentRequestMessage,
VerifyOffererAccount,
CreateAndSignContract,
PayDeposit,
SendSignedTakerDepositTxAsHex,
ValidateDepositTxPublishedMessage,
TakerCommitDepositTx,
handleBankTransferInitedMessage,
SignAndPublishPayoutTx,
SendPayoutTxToOfferer
}
// provided data
private final TradeMessageService tradeMessageService;
private final WalletService walletService;
private final BlockChainService blockChainService;
private final SignatureService signatureService;
// provided
private final Trade trade;
// derived
private final Offer offer;
private final String tradeId;
private final BankAccount bankAccount;
private final String accountId;
private final PublicKey messagePublicKey;
private final Coin tradeAmount;
private final String tradePubKeyAsHex;
private final ECKey accountKey;
private final PublicKey offererMessagePublicKey;
private final Coin securityDeposit;
private final String arbitratorPubKey;
private final PublicKey offererMessagePublicKey;
// written/read by task
private Peer peer;
// written by messages, read by tasks
private String peersAccountId;
private BankAccount peersBankAccount;
private String peersPubKey;
private String preparedPeersDepositTxAsHex;
private long peersTxOutIndex;
private String depositTxAsHex;
private Transaction signedTakerDepositTx;
private Transaction payoutTx;
private String payoutTxAsHex;
private Coin takerPaybackAmount;
private String peersPubKey;
private long peersTxOutIndex;
private String offererSignatureR;
private String offererSignatureS;
private Coin offererPaybackAmount;
private Coin takerPaybackAmount;
private String offererPayoutAddress;
private Transaction signedTakerDepositTx;
private TradeMessage tradeMessage;
// state
private State state;
public SellerAsTakerModel(Trade trade,
TradeMessageService tradeMessageService,
WalletService walletService,
BlockChainService blockChainService,
SignatureService signatureService,
User user) {
super(trade.getOffer(),
tradeMessageService,
walletService,
blockChainService,
signatureService,
user);
public SellerTakesOfferModel(Trade trade,
TradeMessageService tradeMessageService,
WalletService walletService,
BlockChainService blockChainService,
SignatureService signatureService,
User user) {
super(trade);
this.tradeMessageService = tradeMessageService;
this.walletService = walletService;
this.blockChainService = blockChainService;
this.signatureService = signatureService;
offer = trade.getOffer();
tradeId = trade.getId();
this.trade = trade;
tradeAmount = trade.getTradeAmount();
securityDeposit = trade.getSecurityDeposit();
//TODO use 1. for now
arbitratorPubKey = trade.getOffer().getArbitrators().get(0).getPubKeyAsHex();
offererMessagePublicKey = offer.getMessagePublicKey();
bankAccount = user.getCurrentBankAccount().get();
accountId = user.getAccountId();
messagePublicKey = user.getMessagePublicKey();
tradePubKeyAsHex = walletService.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
accountKey = walletService.getRegistrationAddressEntry().getKey();
state = State.Init;
tradePubKeyAsHex = walletService.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
}
// Setters
public void setPeer(Peer peer) {
this.peer = peer;
}
public void setPeersAccountId(String peersAccountId) {
this.peersAccountId = peersAccountId;
}
public void setPeersBankAccount(BankAccount peersBankAccount) {
this.peersBankAccount = peersBankAccount;
}
public void setPeersPubKey(String peersPubKey) {
this.peersPubKey = peersPubKey;
}
public void setPreparedPeersDepositTxAsHex(String preparedPeersDepositTxAsHex) {
this.preparedPeersDepositTxAsHex = preparedPeersDepositTxAsHex;
}
public void setPeersTxOutIndex(long peersTxOutIndex) {
this.peersTxOutIndex = peersTxOutIndex;
}
public void setDepositTxAsHex(String depositTxAsHex) {
this.depositTxAsHex = depositTxAsHex;
}
public void setOffererSignatureR(String offererSignatureR) {
this.offererSignatureR = offererSignatureR;
}
public void setOffererSignatureS(String offererSignatureS) {
this.offererSignatureS = offererSignatureS;
}
public void setOffererPaybackAmount(Coin offererPaybackAmount) {
this.offererPaybackAmount = offererPaybackAmount;
}
public void setTakerPaybackAmount(Coin takerPaybackAmount) {
this.takerPaybackAmount = takerPaybackAmount;
}
public void setOffererPayoutAddress(String offererPayoutAddress) {
this.offererPayoutAddress = offererPayoutAddress;
}
public void setState(State state) {
this.state = state;
}
public void setTradeMessage(TradeMessage tradeMessage) {
this.tradeMessage = tradeMessage;
}
public void setSignedTakerDepositTx(Transaction signedTakerDepositTx) {
this.signedTakerDepositTx = signedTakerDepositTx;
}
// Getters
// getter/setter
public Trade getTrade() {
return trade;
}
public TradeMessageService getTradeMessageService() {
return tradeMessageService;
}
public WalletService getWalletService() {
return walletService;
}
public BlockChainService getBlockChainService() {
return blockChainService;
}
public SignatureService getSignatureService() {
return signatureService;
}
public Offer getOffer() {
return offer;
}
public String getTradeId() {
return tradeId;
}
public BankAccount getBankAccount() {
return bankAccount;
}
public String getAccountId() {
return accountId;
}
public PublicKey getMessagePublicKey() {
return messagePublicKey;
}
public Coin getTradeAmount() {
return tradeAmount;
}
public String getTradePubKeyAsHex() {
return tradePubKeyAsHex;
}
public ECKey getAccountKey() {
return accountKey;
public Coin getSecurityDeposit() {
return securityDeposit;
}
public PublicKey getOffererMessagePublicKey() {
return offererMessagePublicKey;
}
public Coin getSecurityDeposit() {
return securityDeposit;
}
public String getArbitratorPubKey() {
return arbitratorPubKey;
}
public Peer getPeer() {
return peer;
}
public String getPeersAccountId() {
return peersAccountId;
public void setPeer(Peer peer) {
this.peer = peer;
}
public BankAccount getPeersBankAccount() {
return peersBankAccount;
public Transaction getPayoutTx() {
return payoutTx;
}
public void setPayoutTx(Transaction payoutTx) {
this.payoutTx = payoutTx;
}
public String getPayoutTxAsHex() {
return payoutTxAsHex;
}
public void setPayoutTxAsHex(String payoutTxAsHex) {
this.payoutTxAsHex = payoutTxAsHex;
}
public String getPeersPubKey() {
return peersPubKey;
}
public void setPeersPubKey(String peersPubKey) {
this.peersPubKey = peersPubKey;
}
public String getPreparedPeersDepositTxAsHex() {
return preparedPeersDepositTxAsHex;
}
public void setPreparedPeersDepositTxAsHex(String preparedPeersDepositTxAsHex) {
this.preparedPeersDepositTxAsHex = preparedPeersDepositTxAsHex;
}
public long getPeersTxOutIndex() {
return peersTxOutIndex;
}
public void setPeersTxOutIndex(long peersTxOutIndex) {
this.peersTxOutIndex = peersTxOutIndex;
}
public String getDepositTxAsHex() {
return depositTxAsHex;
}
public void setDepositTxAsHex(String depositTxAsHex) {
this.depositTxAsHex = depositTxAsHex;
}
public String getOffererSignatureR() {
return offererSignatureR;
}
public void setOffererSignatureR(String offererSignatureR) {
this.offererSignatureR = offererSignatureR;
}
public String getOffererSignatureS() {
return offererSignatureS;
}
public void setOffererSignatureS(String offererSignatureS) {
this.offererSignatureS = offererSignatureS;
}
public Coin getOffererPaybackAmount() {
return offererPaybackAmount;
}
public void setOffererPaybackAmount(Coin offererPaybackAmount) {
this.offererPaybackAmount = offererPaybackAmount;
}
public Coin getTakerPaybackAmount() {
return takerPaybackAmount;
}
public void setTakerPaybackAmount(Coin takerPaybackAmount) {
this.takerPaybackAmount = takerPaybackAmount;
}
public String getOffererPayoutAddress() {
return offererPayoutAddress;
}
public State getState() {
return state;
public void setOffererPayoutAddress(String offererPayoutAddress) {
this.offererPayoutAddress = offererPayoutAddress;
}
public TradeMessage getTradeMessage() {
return tradeMessage;
} public Transaction getSignedTakerDepositTx() {
public Transaction getSignedTakerDepositTx() {
return signedTakerDepositTx;
}
public void setSignedTakerDepositTx(Transaction signedTakerDepositTx) {
this.signedTakerDepositTx = signedTakerDepositTx;
}
}

@ -20,7 +20,6 @@ package io.bitsquare.trade.protocol.trade.taker;
import io.bitsquare.network.Message;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeTaskRunner;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
@ -36,10 +35,10 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTxAsH
import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.ValidateBankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ValidateDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ValidateRespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ValidateTakerDepositPaymentRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessTakerDepositPaymentRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount;
@ -56,24 +55,29 @@ import static io.bitsquare.util.Validator.nonEmptyStringOf;
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
*/
public class SellerTakesOfferProtocol {
private static final Logger log = LoggerFactory.getLogger(SellerTakesOfferProtocol.class);
public class SellerAsTakerProtocol {
private static final Logger log = LoggerFactory.getLogger(SellerAsTakerProtocol.class);
private final SellerTakesOfferModel model;
private final SellerAsTakerModel model;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public SellerTakesOfferProtocol(SellerTakesOfferModel model) {
public SellerAsTakerProtocol(SellerAsTakerModel model) {
this.model = model;
}
public void start() {
///////////////////////////////////////////////////////////////////////////////////////////
// UI event handling
///////////////////////////////////////////////////////////////////////////////////////////
public void handleRequestTakeOfferUIEvent() {
model.getTradeMessageService().addMessageHandler(this::handleMessage);
TradeTaskRunner<SellerTakesOfferModel> sequence1 = new TradeTaskRunner<>(model,
SellerAsTakerTaskRunner<SellerAsTakerModel> sequence = new SellerAsTakerTaskRunner<>(model,
() -> {
log.debug("sequence1 completed");
},
@ -81,16 +85,17 @@ public class SellerTakesOfferProtocol {
log.error(message);
}
);
sequence1.addTasks(
sequence.addTasks(
GetPeerAddress.class,
RequestTakeOffer.class
);
sequence1.run();
sequence.run();
}
public void cleanup() {
model.getTradeMessageService().removeMessageHandler(this::handleMessage);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
@ -103,16 +108,16 @@ public class SellerTakesOfferProtocol {
nonEmptyStringOf(tradeMessage.getTradeId());
if (tradeMessage instanceof RespondToTakeOfferRequestMessage) {
handleTradeMessage((RespondToTakeOfferRequestMessage) tradeMessage);
handleRespondToTakeOfferRequestMessage((RespondToTakeOfferRequestMessage) tradeMessage);
}
else if (tradeMessage instanceof TakerDepositPaymentRequestMessage) {
handleTradeMessage((TakerDepositPaymentRequestMessage) tradeMessage);
handleTakerDepositPaymentRequestMessage((TakerDepositPaymentRequestMessage) tradeMessage);
}
else if (tradeMessage instanceof DepositTxPublishedMessage) {
handleTradeMessage((DepositTxPublishedMessage) tradeMessage);
handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
}
else if (tradeMessage instanceof BankTransferInitedMessage) {
handleTradeMessage((BankTransferInitedMessage) tradeMessage);
handleBankTransferInitedMessage((BankTransferInitedMessage) tradeMessage);
}
else {
log.error("Incoming message not supported. " + tradeMessage);
@ -120,10 +125,10 @@ public class SellerTakesOfferProtocol {
}
}
private void handleTradeMessage(RespondToTakeOfferRequestMessage tradeMessage) {
private void handleRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
TradeTaskRunner<SellerTakesOfferModel> sequence2 = new TradeTaskRunner<>(model,
SellerAsTakerTaskRunner<SellerAsTakerModel> sequence2 = new SellerAsTakerTaskRunner<>(model,
() -> {
log.debug("sequence2 completed");
},
@ -132,17 +137,17 @@ public class SellerTakesOfferProtocol {
}
);
sequence2.addTasks(
ValidateRespondToTakeOfferRequestMessage.class,
ProcessRespondToTakeOfferRequestMessage.class,
PayTakeOfferFee.class,
SendTakeOfferFeePayedMessage.class
);
sequence2.run();
}
private void handleTradeMessage(TakerDepositPaymentRequestMessage tradeMessage) {
private void handleTakerDepositPaymentRequestMessage(TakerDepositPaymentRequestMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
TradeTaskRunner<SellerTakesOfferModel> sequence3 = new TradeTaskRunner<>(model,
SellerAsTakerTaskRunner<SellerAsTakerModel> sequence3 = new SellerAsTakerTaskRunner<>(model,
() -> {
log.debug("sequence3 completed");
},
@ -151,7 +156,7 @@ public class SellerTakesOfferProtocol {
}
);
sequence3.addTasks(
ValidateTakerDepositPaymentRequestMessage.class,
ProcessTakerDepositPaymentRequestMessage.class,
VerifyOffererAccount.class,
CreateAndSignContract.class,
PayDeposit.class,
@ -160,10 +165,10 @@ public class SellerTakesOfferProtocol {
sequence3.run();
}
private void handleTradeMessage(DepositTxPublishedMessage tradeMessage) {
private void handleDepositTxPublishedMessage(DepositTxPublishedMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
TradeTaskRunner<SellerTakesOfferModel> sequence4 = new TradeTaskRunner<>(model,
SellerAsTakerTaskRunner<SellerAsTakerModel> sequence4 = new SellerAsTakerTaskRunner<>(model,
() -> {
log.debug("sequence4 completed");
},
@ -172,16 +177,16 @@ public class SellerTakesOfferProtocol {
}
);
sequence4.addTasks(
ValidateDepositTxPublishedMessage.class,
ProcessDepositTxPublishedMessage.class,
TakerCommitDepositTx.class
);
sequence4.run();
}
private void handleTradeMessage(BankTransferInitedMessage tradeMessage) {
private void handleBankTransferInitedMessage(BankTransferInitedMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
TradeTaskRunner<SellerTakesOfferModel> sequence5 = new TradeTaskRunner<>(model,
SellerAsTakerTaskRunner<SellerAsTakerModel> sequence5 = new SellerAsTakerTaskRunner<>(model,
() -> {
log.debug("sequence5 completed");
model.getTrade().setState(Trade.State.FIAT_PAYMENT_STARTED);
@ -190,7 +195,7 @@ public class SellerTakesOfferProtocol {
log.error(message);
}
);
sequence5.addTasks(ValidateBankTransferInitedMessage.class);
sequence5.addTasks(ProcessBankTransferInitedMessage.class);
sequence5.run();
}
@ -200,7 +205,7 @@ public class SellerTakesOfferProtocol {
// User clicked the "bank transfer received" button, so we release the funds for pay out
public void handleFiatReceivedUIEvent() {
TradeTaskRunner<SellerTakesOfferModel> sequence6 = new TradeTaskRunner<>(model,
SellerAsTakerTaskRunner<SellerAsTakerModel> sequence6 = new SellerAsTakerTaskRunner<>(model,
() -> {
log.debug("sequence6 completed");
},

@ -0,0 +1,42 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.taker;
import io.bitsquare.trade.Trade;
import io.bitsquare.util.handlers.FaultHandler;
import io.bitsquare.util.handlers.ResultHandler;
import io.bitsquare.util.tasks.TaskRunner;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SellerAsTakerTaskRunner<T extends SellerAsTakerModel> extends TaskRunner<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SellerAsTakerTaskRunner.class);
public SellerAsTakerTaskRunner(T sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
super(sharedModel, resultHandler, faultHandler);
}
@Override
public void handleFault(String message, @NotNull Throwable throwable) {
sharedModel.getTrade().setState(Trade.State.FAILED);
super.handleFault(message, throwable);
}
}

@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.Utilities;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -27,10 +27,10 @@ import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateAndSignContract extends Task<SellerTakesOfferModel> {
public class CreateAndSignContract extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
public CreateAndSignContract(TaskRunner taskHandler, SellerTakesOfferModel model) {
public CreateAndSignContract(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}

@ -20,7 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -30,10 +30,10 @@ import java.security.PublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GetPeerAddress extends Task<SellerTakesOfferModel> {
public class GetPeerAddress extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
public GetPeerAddress(TaskRunner taskHandler, SellerTakesOfferModel model) {
public GetPeerAddress(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}

@ -17,7 +17,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -28,10 +28,10 @@ import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayDeposit extends Task<SellerTakesOfferModel> {
public class PayDeposit extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
public PayDeposit(TaskRunner taskHandler, SellerTakesOfferModel model) {
public PayDeposit(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@ -47,7 +47,7 @@ public class PayDeposit extends Task<SellerTakesOfferModel> {
model.getTradePubKeyAsHex(),
model.getArbitratorPubKey(),
model.getPreparedPeersDepositTxAsHex(),
model.getTradeId());
model.getTrade().getId());
model.setSignedTakerDepositTx(signedTakerDepositTx);

@ -17,7 +17,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -31,17 +31,17 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayTakeOfferFee extends Task<SellerTakesOfferModel> {
public class PayTakeOfferFee extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(PayTakeOfferFee.class);
public PayTakeOfferFee(TaskRunner taskHandler, SellerTakesOfferModel model) {
public PayTakeOfferFee(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
model.getWalletService().payTakeOfferFee(model.getTradeId(), new FutureCallback<Transaction>() {
model.getWalletService().payTakeOfferFee(model.getTrade().getId(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString());

@ -18,28 +18,26 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkState;
import static io.bitsquare.util.Validator.*;
public class ValidateBankTransferInitedMessage extends Task<SellerTakesOfferModel> {
private static final Logger log = LoggerFactory.getLogger(ValidateBankTransferInitedMessage.class);
public class ProcessBankTransferInitedMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessBankTransferInitedMessage.class);
public ValidateBankTransferInitedMessage(TaskRunner taskHandler, SellerTakesOfferModel model) {
public ProcessBankTransferInitedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkState(model.getTrade().getPreviousTask() == TakerCommitDepositTx.class);
checkTradeId(model.getTradeId(), model.getTradeMessage());
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
BankTransferInitedMessage message = (BankTransferInitedMessage) model.getTradeMessage();
model.setDepositTxAsHex(nonEmptyStringOf(message.getDepositTxAsHex()));
@ -49,7 +47,7 @@ public class ValidateBankTransferInitedMessage extends Task<SellerTakesOfferMode
model.setTakerPaybackAmount(positiveCoinOf(nonZeroCoinOf(message.getTakerPaybackAmount())));
model.setOffererPayoutAddress(nonEmptyStringOf(message.getOffererPayoutAddress()));
// TODO listener.onBankTransferInited(message.getTradeId());
// TODO listener.onBankTransferInited(message.getTrade().getId());
complete();
} catch (Throwable t) {
failed(t);

@ -18,28 +18,26 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkState;
import static io.bitsquare.util.Validator.*;
public class ValidateDepositTxPublishedMessage extends Task<SellerTakesOfferModel> {
private static final Logger log = LoggerFactory.getLogger(ValidateDepositTxPublishedMessage.class);
public class ProcessDepositTxPublishedMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessDepositTxPublishedMessage.class);
public ValidateDepositTxPublishedMessage(TaskRunner taskHandler, SellerTakesOfferModel model) {
public ProcessDepositTxPublishedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkState(model.getTrade().getPreviousTask() == SendSignedTakerDepositTxAsHex.class);
checkTradeId(model.getTradeId(), model.getTradeMessage());
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
DepositTxPublishedMessage message = (DepositTxPublishedMessage) model.getTradeMessage();
model.setDepositTxAsHex(nonEmptyStringOf(message.getDepositTxAsHex()));

@ -19,28 +19,26 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkState;
import static io.bitsquare.util.Validator.checkTradeId;
public class ValidateRespondToTakeOfferRequestMessage extends Task<SellerTakesOfferModel> {
private static final Logger log = LoggerFactory.getLogger(ValidateRespondToTakeOfferRequestMessage.class);
public class ProcessRespondToTakeOfferRequestMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessRespondToTakeOfferRequestMessage.class);
public ValidateRespondToTakeOfferRequestMessage(TaskRunner taskHandler, SellerTakesOfferModel model) {
public ProcessRespondToTakeOfferRequestMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkState(model.getTrade().getPreviousTask() == RequestTakeOffer.class);
checkTradeId(model.getTradeId(), model.getTradeMessage());
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
if (((RespondToTakeOfferRequestMessage) model.getTradeMessage()).isTakeOfferRequestAccepted()) {
model.getTrade().setState(Trade.State.OFFERER_ACCEPTED);

@ -18,28 +18,27 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.protocol.trade.offerer.messages.TakerDepositPaymentRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*;
public class ValidateTakerDepositPaymentRequestMessage extends Task<SellerTakesOfferModel> {
private static final Logger log = LoggerFactory.getLogger(ValidateTakerDepositPaymentRequestMessage.class);
public class ProcessTakerDepositPaymentRequestMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessTakerDepositPaymentRequestMessage.class);
public ValidateTakerDepositPaymentRequestMessage(TaskRunner taskHandler, SellerTakesOfferModel model) {
public ProcessTakerDepositPaymentRequestMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
try {
checkState(model.getTrade().getPreviousTask() == SendTakeOfferFeePayedMessage.class);
checkTradeId(model.getTradeId(), model.getTradeMessage());
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
TakerDepositPaymentRequestMessage message = (TakerDepositPaymentRequestMessage) model.getTradeMessage();
model.setPeersAccountId(nonEmptyStringOf(message.getAccountId()));
model.setPeersBankAccount(checkNotNull(message.getBankAccount()));

@ -18,7 +18,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -26,16 +26,16 @@ import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RequestTakeOffer extends Task<SellerTakesOfferModel> {
public class RequestTakeOffer extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(RequestTakeOffer.class);
public RequestTakeOffer(TaskRunner taskHandler, SellerTakesOfferModel model) {
public RequestTakeOffer(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
model.getTradeMessageService().sendMessage(model.getPeer(), new RequestTakeOfferMessage(model.getTradeId()),
model.getTradeMessageService().sendMessage(model.getPeer(), new RequestTakeOfferMessage(model.getTrade().getId()),
new SendMessageListener() {
@Override
public void handleResult() {

@ -18,7 +18,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -26,16 +26,16 @@ import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendPayoutTxToOfferer extends Task<SellerTakesOfferModel> {
public class SendPayoutTxToOfferer extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class);
public SendPayoutTxToOfferer(TaskRunner taskHandler, SellerTakesOfferModel model) {
public SendPayoutTxToOfferer(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(model.getTradeId(), model.getPayoutTxAsHex());
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(model.getTrade().getId(), model.getPayoutTxAsHex());
model.getTradeMessageService().sendMessage(model.getPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {

@ -18,7 +18,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -29,10 +29,10 @@ import org.bitcoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendSignedTakerDepositTxAsHex extends Task<SellerTakesOfferModel> {
public class SendSignedTakerDepositTxAsHex extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
public SendSignedTakerDepositTxAsHex(TaskRunner taskHandler, SellerTakesOfferModel model) {
public SendSignedTakerDepositTxAsHex(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@ -42,7 +42,7 @@ public class SendSignedTakerDepositTxAsHex extends Task<SellerTakesOfferModel> {
long takerTxOutIndex = model.getSignedTakerDepositTx().getInput(1).getOutpoint().getIndex();
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(
model.getTradeId(),
model.getTrade().getId(),
model.getBankAccount(),
model.getAccountId(),
model.getMessagePublicKey(),
@ -51,7 +51,7 @@ public class SendSignedTakerDepositTxAsHex extends Task<SellerTakesOfferModel> {
Utils.HEX.encode(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize()),
model.getTrade().getContractAsJson(),
model.getTrade().getTakerContractSignature(),
model.getWalletService().getAddressInfoByTradeID(model.getTradeId()).getAddressString(),
model.getWalletService().getAddressInfoByTradeID(model.getTrade().getId()).getAddressString(),
takerTxOutIndex,
model.getPeersTxOutIndex());

@ -18,7 +18,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -26,17 +26,17 @@ import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendTakeOfferFeePayedMessage extends Task<SellerTakesOfferModel> {
public class SendTakeOfferFeePayedMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SendTakeOfferFeePayedMessage.class);
public SendTakeOfferFeePayedMessage(TaskRunner taskHandler, SellerTakesOfferModel model) {
public SendTakeOfferFeePayedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void run() {
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(
model.getTradeId(),
model.getTrade().getId(),
model.getTrade().getTakeOfferFeeTxId(),
model.getTradeAmount(),
model.getTradePubKeyAsHex()

@ -18,7 +18,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -33,10 +33,10 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishPayoutTx extends Task<SellerTakesOfferModel> {
public class SignAndPublishPayoutTx extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
public SignAndPublishPayoutTx(TaskRunner taskHandler, SellerTakesOfferModel model) {
public SignAndPublishPayoutTx(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@ -49,7 +49,7 @@ public class SignAndPublishPayoutTx extends Task<SellerTakesOfferModel> {
model.getOffererPaybackAmount(),
model.getTakerPaybackAmount(),
model.getOffererPayoutAddress(),
model.getTradeId(),
model.getTrade().getId(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {

@ -18,7 +18,7 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
@ -27,10 +27,10 @@ import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerCommitDepositTx extends Task<SellerTakesOfferModel> {
public class TakerCommitDepositTx extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(TakerCommitDepositTx.class);
public TakerCommitDepositTx(TaskRunner taskHandler, SellerTakesOfferModel model) {
public TakerCommitDepositTx(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}

@ -17,17 +17,17 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyOfferFeePayment extends Task<SellerTakesOfferModel> {
public class VerifyOfferFeePayment extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(VerifyOfferFeePayment.class);
public VerifyOfferFeePayment(TaskRunner taskHandler, SellerTakesOfferModel model) {
public VerifyOfferFeePayment(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}

@ -17,17 +17,17 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.tasks.Task;
import io.bitsquare.util.tasks.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyOffererAccount extends Task<SellerTakesOfferModel> {
public class VerifyOffererAccount extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
public VerifyOffererAccount(TaskRunner taskHandler, SellerTakesOfferModel model) {
public VerifyOffererAccount(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}