Split takeofferfee creation and broadcast

This commit is contained in:
Manfred Karrer 2015-03-17 11:11:57 +01:00
parent 6e9539dff8
commit 9a0e174099
26 changed files with 292 additions and 174 deletions

@ -33,7 +33,7 @@ public class FeePolicy {
// TODO: Change REGISTRATION_FEE to 0.00001 (See https://github.com/bitsquare/bitsquare/issues/228)
public static final Coin REGISTRATION_FEE = TX_FEE.add(TX_FEE);
public static final Coin CREATE_OFFER_FEE = Coin.valueOf(10000000); // 0.1 BTC
public static final Coin CREATE_OFFER_FEE = Coin.valueOf(1000000); // 0.01 BTC
public static final Coin TAKE_OFFER_FEE = CREATE_OFFER_FEE;
private final BitcoinNetwork bitcoinNetwork;

@ -114,7 +114,7 @@ public class TradeWalletService {
Futures.addCallback(future, callback);
}
public void payTakeOfferFee(AddressEntry addressEntry, FutureCallback<Transaction> callback) throws InsufficientMoneyException {
public Transaction createTakeOfferFeeTx(AddressEntry addressEntry) throws InsufficientMoneyException {
Transaction takeOfferFeeTx = new Transaction(params);
Coin fee = FeePolicy.TAKE_OFFER_FEE.subtract(FeePolicy.TX_FEE);
takeOfferFeeTx.addOutput(fee, feePolicy.getAddressForTakeOfferFee());
@ -125,10 +125,14 @@ public class TradeWalletService {
// wait for 1 confirmation)
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry, true);
sendRequest.changeAddress = addressEntry.getAddress();
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, callback);
wallet.completeTx(sendRequest);
printTxWithInputs("takeOfferFeeTx", takeOfferFeeTx);
return takeOfferFeeTx;
}
public void broadcastTakeOfferFeeTx(Transaction takeOfferFeeTx, FutureCallback<Transaction> callback) throws InsufficientMoneyException {
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(takeOfferFeeTx);
Futures.addCallback(future, callback);
}

@ -30,7 +30,7 @@ import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs
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.ProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RequestDepositPayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferStartedMessage;
@ -43,7 +43,7 @@ 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.SellerAsTakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.PayTakeOfferFee;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
@ -51,7 +51,7 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRespondToTakeOfferRe
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
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.TakerCreatesAndSignsDepositTx;
@ -109,7 +109,7 @@ public class DebugView extends InitializableView {
ProcessRequestTakeOfferMessage.class,
RespondToTakeOfferRequest.class,
ProcessTakeOfferFeePayedMessage.class,
ProcessRequestDepositTxInputsMessage.class,
GetOffererDepositTxInputs.class,
RequestDepositPayment.class,
@ -134,8 +134,8 @@ public class DebugView extends InitializableView {
RequestTakeOffer.class,
ProcessRespondToTakeOfferRequestMessage.class,
PayTakeOfferFee.class,
SendTakeOfferFeePayedMessage.class,
CreateTakeOfferFeeTx.class,
SendRequestDepositTxInputsMessage.class,
ProcessRequestDepositPaymentMessage.class,
VerifyOffererAccount.class,

@ -17,6 +17,8 @@
package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.FxmlView;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.InputTextField;
@ -33,8 +35,6 @@ import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.closed.ClosedTradesView;
import io.bitsquare.locale.BSResources;
import io.bitsquare.util.Utilities;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.FxmlView;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
@ -106,6 +106,9 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
setVolumeColumnCellFactory();
setDateColumnCellFactory();
//TODO just temp for testing
withdrawAddressTextField.setText("muZkzie5UCaH51P1U9WGWsgejTJQweamai");
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.setPlaceholder(new Label("No pending trades available"));

@ -528,7 +528,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
break;
case OFFERER_OFFLINE:
case NOT_AVAILABLE:
case AVAILABILITY_CHECK_FAILED:
case FAULT:
case REMOVED:
iconView.setId("image-offer_state_not_available");
break;
@ -541,7 +541,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
super.updateItem(item, empty);
if (item != null) {
stateProperty = item.getOffer().getStateProperty();
stateProperty = item.getOffer().stateProperty();
this.stateChangeListener = (ov, o, n) -> updateIcon(item);
stateProperty.addListener(stateChangeListener);
updateIcon(item);

@ -130,7 +130,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
});
updateBalance(walletService.getBalanceForAddress(addressEntry.getAddress()));
offer.getStateProperty().addListener((observable, oldValue, newValue) -> {
offer.stateProperty().addListener((observable, oldValue, newValue) -> {
offerIsAvailable.set(newValue);
});
tradeManager.checkOfferAvailability(offer);
@ -152,7 +152,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
case OFFERER_REJECTED:
requestTakeOfferErrorMessage.set("Take offer request got rejected. Maybe another trader has taken the offer in the meantime.");
break;
case TAKE_OFFER_FEE_PAID:
case TAKE_OFFER_FEE_TX_CREATED:
break;
case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED:
@ -169,7 +169,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
break;
case FIAT_PAYMENT_STARTED:
break;
case TAKE_OFFER_FEE_PAYMENT_FAILED:
case TAKE_OFFER_FEE_PUBLISH_FAILED:
requestTakeOfferErrorMessage.set("An error occurred when paying the trade fee." + errorMessage);
break;
case MESSAGE_SENDING_FAILED:

@ -186,7 +186,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
Popups.openWarningPopup("You cannot take that offer", "The offer was already taken by another trader.");
Platform.runLater(this::close);
break;
case AVAILABILITY_CHECK_FAILED:
case FAULT:
Popups.openWarningPopup("You cannot take that offer", "The check for the offer availability failed.");
Platform.runLater(this::close);
break;

@ -51,10 +51,10 @@ public class Offer implements Serializable {
public enum State {
UNKNOWN,
AVAILABLE,
OFFERER_OFFLINE,
AVAILABLE,
NOT_AVAILABLE,
AVAILABILITY_CHECK_FAILED,
FAULT,
REMOVED
}
@ -125,7 +125,7 @@ public class Offer implements Serializable {
creationDate = new Date();
state = State.UNKNOWN;
getStateProperty().set(state);
stateProperty().set(state);
}
@ -135,7 +135,7 @@ public class Offer implements Serializable {
public void setState(State state) {
this.state = state;
getStateProperty().set(state);
stateProperty().set(state);
}
@ -237,7 +237,7 @@ public class Offer implements Serializable {
return state;
}
public ObjectProperty<State> getStateProperty() {
public ObjectProperty<State> stateProperty() {
if (stateProperty == null)
stateProperty = new SimpleObjectProperty<>(state);
return stateProperty;

@ -25,6 +25,7 @@ import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// Offerer has his own offers wrapped in that OpenOffer object. Taker never has an OpenOffer object.
public class OpenOffer implements Serializable {
private static final long serialVersionUID = -7523483764145982933L;

@ -33,6 +33,7 @@ import javafx.beans.property.SimpleObjectProperty;
public class Trade implements Serializable {
private static final long serialVersionUID = -8275323072940974077L;
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
@ -41,9 +42,10 @@ public class Trade implements Serializable {
OPEN,
OFFERER_ACCEPTED,
OFFERER_REJECTED, /* For taker only*/
TAKE_OFFER_FEE_PAYMENT_FAILED,
TAKE_OFFER_FEE_PAID,
TAKE_OFFER_FEE_PUBLISH_FAILED,
TAKE_OFFER_FEE_TX_CREATED,
DEPOSIT_PUBLISHED,
TAKE_OFFER_FEE_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
FIAT_PAYMENT_RECEIVED,
@ -64,7 +66,6 @@ public class Trade implements Serializable {
private final Offer offer;
private final Date date;
private String takeOfferFeeTxID;
private Contract contract;
private String contractAsJson;
private String takerContractSignature;
@ -102,10 +103,6 @@ public class Trade implements Serializable {
this.takerContractSignature = takerSignature;
}
public void setTakeOfferFeeTxID(String takeOfferFeeTxID) {
this.takeOfferFeeTxID = takeOfferFeeTxID;
}
public Coin getTradeAmount() {
return tradeAmount;
}
@ -178,10 +175,6 @@ public class Trade implements Serializable {
return offer;
}
public String getTakeOfferFeeTxId() {
return takeOfferFeeTxID;
}
public String getContractAsJson() {
return contractAsJson;
}

@ -17,11 +17,12 @@
package io.bitsquare.trade;
import io.bitsquare.user.AccountSettings;
import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.network.Message;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Direction;
@ -41,9 +42,8 @@ import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
import io.bitsquare.user.AccountSettings;
import io.bitsquare.user.User;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
@ -201,6 +201,30 @@ public class TradeManager {
Trade trade = createTrade(offer);
trade.setTradeAmount(amount);
offer.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue);
switch (newValue) {
case UNKNOWN:
break;
case AVAILABLE:
break;
case OFFERER_OFFLINE:
case NOT_AVAILABLE:
case FAULT:
removeFailedTrade(trade);
break;
case REMOVED:
if (oldValue != Offer.State.AVAILABLE) {
removeFailedTrade(trade);
}
break;
default:
log.error("Unhandled trade state: " + newValue);
break;
}
});
// TODO check
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue);
@ -208,7 +232,7 @@ public class TradeManager {
case OPEN:
break;
case OFFERER_ACCEPTED:
case TAKE_OFFER_FEE_PAID:
case TAKE_OFFER_FEE_TX_CREATED:
case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED:
case FIAT_PAYMENT_STARTED:
@ -382,7 +406,7 @@ public class TradeManager {
case OPEN:
break;
case OFFERER_ACCEPTED: // only taker side
case TAKE_OFFER_FEE_PAID:
case TAKE_OFFER_FEE_TX_CREATED:
case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED:
case FIAT_PAYMENT_STARTED:
@ -391,7 +415,7 @@ public class TradeManager {
persistPendingTrades();
break;
case OFFERER_REJECTED:
case TAKE_OFFER_FEE_PAYMENT_FAILED:
case TAKE_OFFER_FEE_PUBLISH_FAILED:
case MESSAGE_SENDING_FAILED:
case FAULT:
removeFailedTrade(trade);
@ -418,11 +442,10 @@ public class TradeManager {
}
private void closeTrade(Trade trade, boolean failed) {
if (!pendingTrades.containsKey(trade.getId()))
log.error("That must never happen: trades does not contain the trade with the ID " + trade.getId());
pendingTrades.remove(trade.getId());
persistPendingTrades();
if (pendingTrades.containsKey(trade.getId())) {
pendingTrades.remove(trade.getId());
persistPendingTrades();
}
if (sellerAsTakerProtocolMap.containsKey(trade.getId())) {
sellerAsTakerProtocolMap.get(trade.getId()).cleanup();
@ -434,8 +457,10 @@ public class TradeManager {
}
if (!failed) {
closedTrades.put(trade.getId(), trade);
persistClosedTrades();
if (!closedTrades.containsKey(trade.getId())) {
closedTrades.put(trade.getId(), trade);
persistClosedTrades();
}
}
/*else {
// TODO add failed trades to history

@ -17,11 +17,11 @@
package io.bitsquare.trade.protocol.availability.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -37,22 +37,26 @@ public class ProcessReportOfferAvailabilityMessage extends Task<CheckOfferAvaila
@Override
protected void doRun() {
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = (ReportOfferAvailabilityMessage) model.getMessage();
nonEmptyStringOf(reportOfferAvailabilityMessage.getOfferId());
try {
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = (ReportOfferAvailabilityMessage) model.getMessage();
nonEmptyStringOf(reportOfferAvailabilityMessage.getOfferId());
if (model.getOffer().getState() != Offer.State.REMOVED) {
if (reportOfferAvailabilityMessage.isOfferOpen())
model.getOffer().setState(Offer.State.AVAILABLE);
else
model.getOffer().setState(Offer.State.NOT_AVAILABLE);
if (model.getOffer().getState() != Offer.State.REMOVED) {
if (reportOfferAvailabilityMessage.isOfferOpen())
model.getOffer().setState(Offer.State.AVAILABLE);
else
model.getOffer().setState(Offer.State.NOT_AVAILABLE);
}
complete();
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
failed(t);
}
complete();
}
@Override
protected void updateStateOnFault() {
model.getOffer().setState(Offer.State.AVAILABILITY_CHECK_FAILED);
}
}

@ -17,12 +17,12 @@
package io.bitsquare.trade.protocol.availability.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -36,25 +36,30 @@ public class RequestIsOfferAvailable extends Task<CheckOfferAvailabilityModel> {
@Override
protected void doRun() {
model.getTradeMessageService().sendMessage(model.getPeer(), new RequestIsOfferAvailableMessage(model.getOffer().getId()),
new SendMessageListener() {
@Override
public void handleResult() {
complete();
}
try {
model.getTradeMessageService().sendMessage(model.getPeer(), new RequestIsOfferAvailableMessage(model.getOffer().getId()),
new SendMessageListener() {
@Override
public void handleResult() {
complete();
}
@Override
public void handleFault() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed();
}
});
@Override
public void handleFault() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed();
}
});
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
failed(t);
}
}
@Override
protected void updateStateOnFault() {
if (model.getOffer().getState() != Offer.State.OFFERER_OFFLINE)
model.getOffer().setState(Offer.State.AVAILABILITY_CHECK_FAILED);
}
}

@ -26,7 +26,7 @@ import io.bitsquare.trade.protocol.trade.offerer.tasks.GetOffererDepositTxInputs
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.ProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RequestDepositPayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferStartedMessage;
@ -40,7 +40,7 @@ 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 io.bitsquare.trade.protocol.trade.taker.messages.RequestDepositTxInputsMessage;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
@ -103,7 +103,7 @@ public class BuyerAsOffererProtocol {
taskRunner.run();
}
private void handleTakeOfferFeePayedMessage(TakeOfferFeePayedMessage tradeMessage) {
private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage) {
model.setTradeMessage(tradeMessage);
BuyerAsOffererTaskRunner<BuyerAsOffererModel> taskRunner = new BuyerAsOffererTaskRunner<>(model,
@ -115,7 +115,7 @@ public class BuyerAsOffererProtocol {
}
);
taskRunner.addTasks(
ProcessTakeOfferFeePayedMessage.class,
ProcessRequestDepositTxInputsMessage.class,
GetOffererDepositTxInputs.class,
RequestDepositPayment.class
);
@ -216,8 +216,8 @@ public class BuyerAsOffererProtocol {
if (tradeMessage instanceof RequestTakeOfferMessage) {
handleRequestTakeOfferMessage((RequestTakeOfferMessage) tradeMessage, peer);
}
else if (tradeMessage instanceof TakeOfferFeePayedMessage) {
handleTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage);
else if (tradeMessage instanceof RequestDepositTxInputsMessage) {
handleRequestDepositTxInputsMessage((RequestDepositTxInputsMessage) tradeMessage);
}
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {

@ -17,11 +17,11 @@
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.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestDepositTxInputsMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -29,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*;
public class ProcessTakeOfferFeePayedMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessTakeOfferFeePayedMessage.class);
public class ProcessRequestDepositTxInputsMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestDepositTxInputsMessage.class);
public ProcessTakeOfferFeePayedMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
public ProcessRequestDepositTxInputsMessage(TaskRunner taskHandler, BuyerAsOffererModel model) {
super(taskHandler, model);
}
@ -41,11 +41,10 @@ public class ProcessTakeOfferFeePayedMessage extends Task<BuyerAsOffererModel> {
try {
checkTradeId(model.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.setTakerPubKey(checkNotNull(takeOfferFeePayedMessage.getTakerPubKey()));
RequestDepositTxInputsMessage requestDepositTxInputsMessage = (RequestDepositTxInputsMessage) model.getTradeMessage();
trade.setTradeAmount(positiveCoinOf(nonZeroCoinOf(requestDepositTxInputsMessage.getTradeAmount())));
model.setTakeOfferFeeTxId(nonEmptyStringOf(requestDepositTxInputsMessage.getTakeOfferFeeTxId()));
model.setTakerPubKey(checkNotNull(requestDepositTxInputsMessage.getTakerPubKey()));
complete();
} catch (Throwable t) {

@ -64,6 +64,7 @@ public class SellerAsTakerModel extends OfferSharedModel {
private FiatAccount takerFiatAccount;
private String takerAccountId;
private ECKey.ECDSASignature offererSignature;
private Transaction takeOfferFeeTx;
public SellerAsTakerModel(Trade trade,
TradeMessageService tradeMessageService,
@ -218,4 +219,12 @@ public class SellerAsTakerModel extends OfferSharedModel {
public void setOffererSignature(ECKey.ECDSASignature offererSignature) {
this.offererSignature = offererSignature;
}
public void setTakeOfferFeeTx(Transaction takeOfferFeeTx) {
this.takeOfferFeeTx = takeOfferFeeTx;
}
public Transaction getTakeOfferFeeTx() {
return takeOfferFeeTx;
}
}

@ -26,17 +26,18 @@ import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferStartedMes
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.GetPeerAddress;
import io.bitsquare.trade.protocol.trade.taker.tasks.PayTakeOfferFee;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTx;
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.TakerCreatesAndSignsDepositTx;
@ -108,8 +109,9 @@ public class SellerAsTakerProtocol {
);
taskRunner.addTasks(
ProcessRespondToTakeOfferRequestMessage.class,
PayTakeOfferFee.class,
SendTakeOfferFeePayedMessage.class
CreateTakeOfferFeeTx.class,
BroadcastTakeOfferFeeTx.class,
SendRequestDepositTxInputsMessage.class
);
taskRunner.run();
}

@ -23,17 +23,17 @@ import org.bitcoinj.core.Coin;
import java.io.Serializable;
public class TakeOfferFeePayedMessage implements Serializable, TradeMessage {
public class RequestDepositTxInputsMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = -5057935061275354312L;
private final String tradeId;
private final Coin tradeAmount;
private final String takeOfferFeeTxID;
private final String takeOfferFeeTxId;
private final byte[] takerPubKey;
public TakeOfferFeePayedMessage(String tradeId, String takeOfferFeeTxID, Coin tradeAmount, byte[] takerPubKey) {
public RequestDepositTxInputsMessage(String tradeId, String takeOfferFeeTxId, Coin tradeAmount, byte[] takerPubKey) {
this.tradeId = tradeId;
this.takeOfferFeeTxID = takeOfferFeeTxID;
this.takeOfferFeeTxId = takeOfferFeeTxId;
this.tradeAmount = tradeAmount;
this.takerPubKey = takerPubKey;
}
@ -48,7 +48,7 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage {
}
public String getTakeOfferFeeTxId() {
return takeOfferFeeTxID;
return takeOfferFeeTxId;
}
public byte[] getTakerPubKey() {

@ -17,10 +17,10 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import org.bitcoinj.core.Transaction;
@ -31,43 +31,44 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayTakeOfferFee extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(PayTakeOfferFee.class);
public class BroadcastTakeOfferFeeTx extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(BroadcastTakeOfferFeeTx.class);
public PayTakeOfferFee(TaskRunner taskHandler, SellerAsTakerModel model) {
public BroadcastTakeOfferFeeTx(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
model.getTradeWalletService().payTakeOfferFee(model.getAddressEntry(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString());
model.getTrade().setTakeOfferFeeTxID(transaction.getHashAsString());
model.getTrade().setState(Trade.State.TAKE_OFFER_FEE_PAID);
model.getTradeWalletService().broadcastTakeOfferFeeTx(model.getTakeOfferFeeTx(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("Take offer fee published successfully. Transaction ID = " + transaction.getHashAsString());
model.getTrade().setState(Trade.State.TAKE_OFFER_FEE_PUBLISHED);
complete();
}
complete();
}
@Override
public void onFailure(@NotNull Throwable t) {
failed(t);
}
});
@Override
public void onFailure(@NotNull Throwable t) {
model.getTrade().setState(Trade.State.TAKE_OFFER_FEE_PUBLISH_FAILED);
failed(t);
}
});
} catch (Exception e) {
appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again.");
appendToErrorMessage(e.getMessage());
model.getTrade().setState(Trade.State.FAULT);
failed(e);
}
}
@Override
protected void updateStateOnFault() {
// As long as the take offer fee was not paid nothing critical happens.
// The take offer process can be repeated so we reset the trade state.
appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again.");
model.getTrade().setTakeOfferFeeTxID(null);
model.getTrade().setState(Trade.State.TAKE_OFFER_FEE_PAYMENT_FAILED);
}
}

@ -17,12 +17,12 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.Utilities;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -39,8 +39,8 @@ public class CreateAndSignContract extends Task<SellerAsTakerModel> {
Trade trade = model.getTrade();
Contract contract = new Contract(
model.getOffer(),
model.getTrade().getTradeAmount(),
trade.getTakeOfferFeeTxId(),
trade.getTradeAmount(),
model.getTakeOfferFeeTx().getHashAsString(),
model.getTakerAccountId(),
model.getAccountId(),
model.getTakerFiatAccount(),

@ -0,0 +1,58 @@
/*
* 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.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateTakeOfferFeeTx extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(CreateTakeOfferFeeTx.class);
public CreateTakeOfferFeeTx(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
Transaction createTakeOfferFeeTx = model.getTradeWalletService().createTakeOfferFeeTx(model.getAddressEntry());
model.setTakeOfferFeeTx(createTakeOfferFeeTx);
model.getTrade().setState(Trade.State.TAKE_OFFER_FEE_TX_CREATED);
complete();
} catch (Exception e) {
appendToErrorMessage(e.getMessage());
model.getTrade().setState(Trade.State.FAULT);
failed(e);
}
}
@Override
protected void updateStateOnFault() {
}
}

@ -17,12 +17,12 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.network.Peer;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -37,29 +37,31 @@ public class GetPeerAddress extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
model.getTradeMessageService().getPeerAddress(model.getOffer().getMessagePublicKey(), new GetPeerAddressListener() {
@Override
public void onResult(Peer peer) {
log.trace("Found peer: " + peer.toString());
try {
model.getTradeMessageService().getPeerAddress(model.getOffer().getMessagePublicKey(), new GetPeerAddressListener() {
@Override
public void onResult(Peer peer) {
model.setOfferer(peer);
model.setOfferer(peer);
complete();
}
complete();
}
@Override
public void onFailed() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
@Override
public void onFailed() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed();
}
});
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
failed();
}
});
failed(t);
}
}
@Override
protected void updateStateOnFault() {
if (model.getOffer().getState() != Offer.State.OFFERER_OFFLINE)
model.getOffer().setState(Offer.State.AVAILABILITY_CHECK_FAILED);
}
}

@ -17,11 +17,12 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -41,20 +42,26 @@ public class ProcessRespondToTakeOfferRequestMessage extends Task<SellerAsTakerM
checkTradeId(model.getId(), model.getTradeMessage());
if (((RespondToTakeOfferRequestMessage) model.getTradeMessage()).isOfferIsAvailable()) {
model.getOffer().setState(Offer.State.AVAILABLE);
model.getTrade().setState(Trade.State.OFFERER_ACCEPTED);
complete();
}
else {
model.getOffer().setState(Offer.State.NOT_AVAILABLE);
model.getTrade().setState(Trade.State.OFFERER_REJECTED);
failed("Requested offer rejected because it is not available anymore.");
}
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
model.getTrade().setState(Trade.State.FAULT);
failed(t);
}
}
@Override
protected void updateStateOnFault() {
model.getTrade().setState(Trade.State.MESSAGE_SENDING_FAILED);
}
}

@ -17,12 +17,12 @@
package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -36,24 +36,29 @@ public class RequestTakeOffer extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
model.getTradeMessageService().sendMessage(model.getOfferer(), new RequestTakeOfferMessage(model.getId()),
new SendMessageListener() {
@Override
public void handleResult() {
complete();
}
try {
model.getTradeMessageService().sendMessage(model.getOfferer(), new RequestTakeOfferMessage(model.getId()),
new SendMessageListener() {
@Override
public void handleResult() {
complete();
}
@Override
public void handleFault() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed();
}
});
@Override
public void handleFault() {
model.getOffer().setState(Offer.State.OFFERER_OFFLINE);
failed();
}
});
} catch (Throwable t) {
model.getOffer().setState(Offer.State.FAULT);
failed(t);
}
}
@Override
protected void updateStateOnFault() {
if (model.getOffer().getState() != Offer.State.OFFERER_OFFLINE)
model.getOffer().setState(Offer.State.AVAILABILITY_CHECK_FAILED);
}
}

@ -20,17 +20,17 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestDepositTxInputsMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendTakeOfferFeePayedMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SendTakeOfferFeePayedMessage.class);
public class SendRequestDepositTxInputsMessage extends Task<SellerAsTakerModel> {
private static final Logger log = LoggerFactory.getLogger(SendRequestDepositTxInputsMessage.class);
public SendTakeOfferFeePayedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
public SendRequestDepositTxInputsMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
super(taskHandler, model);
}
@ -38,9 +38,9 @@ public class SendTakeOfferFeePayedMessage extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(
RequestDepositTxInputsMessage msg = new RequestDepositTxInputsMessage(
model.getId(),
model.getTrade().getTakeOfferFeeTxId(),
model.getTakeOfferFeeTx().getHashAsString(),
model.getTrade().getTradeAmount(),
model.getTakerPubKey()
);

@ -34,7 +34,7 @@ public class VerifyOfferFeePayment extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
//TODO impl. missing
int numOfPeersSeenTx = model.getWalletService().getNumOfPeersSeenTx(model.getTrade().getTakeOfferFeeTxId());
int numOfPeersSeenTx = model.getWalletService().getNumOfPeersSeenTx(model.getTakeOfferFeeTx().getHashAsString());
/* if (numOfPeersSeenTx > 2) {
resultHandler.handleResult();
}*/