Second trade process (WIP)

This commit is contained in:
Manfred Karrer 2015-03-30 23:25:24 +02:00
parent 6e644ae2b7
commit 0700a53561
105 changed files with 4575 additions and 999 deletions

View file

@ -310,22 +310,22 @@ public class TradeWalletService {
return new Result(preparedDepositTx, takerConnectedOutputsForAllInputs, takerOutputs); return new Result(preparedDepositTx, takerConnectedOutputsForAllInputs, takerOutputs);
} }
public void offererSignsAndPublishDepositTx(Transaction takersPreparedDepositTx, public void signAndPublishDepositTx(Transaction preparedDepositTx,
List<TransactionOutput> offererConnectedOutputsForAllInputs, List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> takerConnectedOutputsForAllInputs, List<TransactionOutput> takerConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs, List<TransactionOutput> buyerOutputs,
Coin offererInputAmount, Coin buyerInputAmount,
byte[] offererPubKey, byte[] offererPubKey,
byte[] takerPubKey, byte[] takerPubKey,
byte[] arbitratorPubKey, byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException, FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException,
WalletException { WalletException {
log.trace("offererSignsAndPublishTx called"); log.trace("offererSignsAndPublishTx called");
log.trace("takersPreparedDepositTx " + takersPreparedDepositTx.toString()); log.trace("preparedDepositTx " + preparedDepositTx.toString());
log.trace("offererConnectedOutputsForAllInputs " + offererConnectedOutputsForAllInputs.toString()); log.trace("offererConnectedOutputsForAllInputs " + offererConnectedOutputsForAllInputs.toString());
log.trace("takerConnectedOutputsForAllInputs " + takerConnectedOutputsForAllInputs.toString()); log.trace("takerConnectedOutputsForAllInputs " + takerConnectedOutputsForAllInputs.toString());
log.trace("offererOutputs " + offererOutputs.toString()); log.trace("buyerOutputs " + buyerOutputs.toString());
log.trace("offererInputAmount " + offererInputAmount.toFriendlyString()); log.trace("buyerInputAmount " + buyerInputAmount.toFriendlyString());
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString()); log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString()); log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString()); log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
@ -335,10 +335,10 @@ public class TradeWalletService {
// Check if takers Multisig script is identical to mine // Check if takers Multisig script is identical to mine
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey); Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey);
if (!takersPreparedDepositTx.getOutput(0).getScriptPubKey().equals(p2SHMultiSigOutputScript)) if (!preparedDepositTx.getOutput(0).getScriptPubKey().equals(p2SHMultiSigOutputScript))
throw new TransactionVerificationException("Takers p2SHMultiSigOutputScript does not match to my p2SHMultiSigOutputScript"); throw new TransactionVerificationException("Takers p2SHMultiSigOutputScript does not match to my p2SHMultiSigOutputScript");
// The outpoints are not available from the serialized takersPreparedDepositTx, so we cannot use that tx directly, but we use it to construct a new // The outpoints are not available from the serialized preparedDepositTx, so we cannot use that tx directly, but we use it to construct a new
// depositTx // depositTx
Transaction depositTx = new Transaction(params); Transaction depositTx = new Transaction(params);
@ -358,8 +358,8 @@ public class TradeWalletService {
for (TransactionOutput connectedOutputForInput : takerConnectedOutputsForAllInputs) { for (TransactionOutput connectedOutputForInput : takerConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction()); TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
// We grab the signature from the takersPreparedDepositTx and apply it to the new tx input // We grab the signature from the preparedDepositTx and apply it to the new tx input
TransactionInput takerInput = takersPreparedDepositTx.getInputs().get(offererConnectedOutputsForAllInputs.size()); TransactionInput takerInput = preparedDepositTx.getInputs().get(offererConnectedOutputsForAllInputs.size());
byte[] scriptProgram = takerInput.getScriptSig().getProgram(); byte[] scriptProgram = takerInput.getScriptSig().getProgram();
if (scriptProgram.length == 0) if (scriptProgram.length == 0)
throw new TransactionVerificationException("Inputs from taker not singed."); throw new TransactionVerificationException("Inputs from taker not singed.");
@ -368,8 +368,8 @@ public class TradeWalletService {
depositTx.addInput(transactionInput); depositTx.addInput(transactionInput);
} }
// Add all outputs from takersPreparedDepositTx to depositTx // Add all outputs from preparedDepositTx to depositTx
takersPreparedDepositTx.getOutputs().forEach(depositTx::addOutput); preparedDepositTx.getOutputs().forEach(depositTx::addOutput);
// Sign inputs // Sign inputs
for (int i = 0; i < offererConnectedOutputsForAllInputs.size(); i++) { for (int i = 0; i < offererConnectedOutputsForAllInputs.size(); i++) {
@ -379,11 +379,11 @@ public class TradeWalletService {
} }
// subtract change amount // subtract change amount
for (int i = 1; i < offererOutputs.size() + 1; i++) { for (int i = 1; i < buyerOutputs.size() + 1; i++) {
offererSpendingAmount = offererSpendingAmount.subtract(depositTx.getOutput(i).getValue()); offererSpendingAmount = offererSpendingAmount.subtract(depositTx.getOutput(i).getValue());
} }
if (offererInputAmount.compareTo(offererSpendingAmount) != 0) if (buyerInputAmount.compareTo(offererSpendingAmount) != 0)
throw new TransactionVerificationException("Offerers input amount does not match required value."); throw new TransactionVerificationException("Offerers input amount does not match required value.");
verifyTransaction(depositTx); verifyTransaction(depositTx);
@ -416,11 +416,11 @@ public class TradeWalletService {
return wallet.getTransaction(tx.getHash()); return wallet.getTransaction(tx.getHash());
} }
public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx, public byte[] createAndSignPayoutTx(Transaction depositTx,
Coin offererPayoutAmount, Coin offererPayoutAmount,
Coin takerPayoutAmount, Coin takerPayoutAmount,
AddressEntry offererAddressEntry, AddressEntry buyerAddressEntry,
String takerPayoutAddressString, String sellerPayoutAddressString,
byte[] offererPubKey, byte[] offererPubKey,
byte[] takerPubKey, byte[] takerPubKey,
byte[] arbitratorPubKey) byte[] arbitratorPubKey)
@ -429,24 +429,24 @@ public class TradeWalletService {
log.trace("depositTx " + depositTx.toString()); log.trace("depositTx " + depositTx.toString());
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString()); log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString()); log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
log.trace("offererAddressEntry " + offererAddressEntry.toString()); log.trace("buyerAddressEntry " + buyerAddressEntry.toString());
log.trace("takerPayoutAddressString " + takerPayoutAddressString); log.trace("sellerPayoutAddressString " + sellerPayoutAddressString);
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString()); log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString()); log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString()); log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
if (!Utils.HEX.encode(offererAddressEntry.getPubKey()).equals(Utils.HEX.encode(offererPubKey))) if (!Utils.HEX.encode(buyerAddressEntry.getPubKey()).equals(Utils.HEX.encode(offererPubKey)))
throw new SigningException("OffererPubKey not matching key pair from addressEntry"); throw new SigningException("OffererPubKey not matching key pair from addressEntry");
Transaction preparedPayoutTx = createPayoutTx(depositTx, Transaction preparedPayoutTx = createPayoutTx(depositTx,
offererPayoutAmount, offererPayoutAmount,
takerPayoutAmount, takerPayoutAmount,
offererAddressEntry.getAddressString(), buyerAddressEntry.getAddressString(),
takerPayoutAddressString); sellerPayoutAddressString);
// MS redeemScript // MS redeemScript
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey); Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false); Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = offererAddressEntry.getKeyPair().sign(sigHash).toCanonicalised(); ECKey.ECDSASignature offererSignature = buyerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
verifyTransaction(preparedPayoutTx); verifyTransaction(preparedPayoutTx);
@ -459,12 +459,12 @@ public class TradeWalletService {
return offererSignature.encodeToDER(); return offererSignature.encodeToDER();
} }
public void takerSignsAndPublishPayoutTx(Transaction depositTx, public void signAndPublishPayoutTx(Transaction depositTx,
byte[] offererSignature, byte[] buyerSignature,
Coin offererPayoutAmount, Coin offererPayoutAmount,
Coin takerPayoutAmount, Coin takerPayoutAmount,
String offererAddressString, String buyerAddressString,
AddressEntry takerAddressEntry, AddressEntry sellerAddressEntry,
byte[] offererPubKey, byte[] offererPubKey,
byte[] takerPubKey, byte[] takerPubKey,
byte[] arbitratorPubKey, byte[] arbitratorPubKey,
@ -472,27 +472,27 @@ public class TradeWalletService {
throws AddressFormatException, TransactionVerificationException, WalletException, SigningException { throws AddressFormatException, TransactionVerificationException, WalletException, SigningException {
log.trace("takerSignsAndPublishPayoutTx called"); log.trace("takerSignsAndPublishPayoutTx called");
log.trace("depositTx " + depositTx.toString()); log.trace("depositTx " + depositTx.toString());
log.trace("offererSignature r " + ECKey.ECDSASignature.decodeFromDER(offererSignature).r.toString()); log.trace("buyerSignature r " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).r.toString());
log.trace("offererSignature s " + ECKey.ECDSASignature.decodeFromDER(offererSignature).s.toString()); log.trace("buyerSignature s " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).s.toString());
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString()); log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString()); log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
log.trace("offererAddressString " + offererAddressString); log.trace("buyerAddressString " + buyerAddressString);
log.trace("takerAddressEntry " + takerAddressEntry); log.trace("sellerAddressEntry " + sellerAddressEntry);
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString()); log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString()); log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString()); log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
if (!Utils.HEX.encode(takerAddressEntry.getPubKey()).equals(Utils.HEX.encode(takerPubKey))) if (!Utils.HEX.encode(sellerAddressEntry.getPubKey()).equals(Utils.HEX.encode(takerPubKey)))
throw new SigningException("TakerPubKey not matching key pair from addressEntry"); throw new SigningException("TakerPubKey not matching key pair from addressEntry");
Transaction payoutTx = createPayoutTx(depositTx, Transaction payoutTx = createPayoutTx(depositTx,
offererPayoutAmount, offererPayoutAmount,
takerPayoutAmount, takerPayoutAmount,
offererAddressString, buyerAddressString,
takerAddressEntry.getAddressString()); sellerAddressEntry.getAddressString());
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey); Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false); Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature takerSignature = takerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised(); ECKey.ECDSASignature takerSignature = sellerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
log.trace("takerSignature r " + takerSignature.r.toString()); log.trace("takerSignature r " + takerSignature.r.toString());
log.trace("takerSignature s " + takerSignature.s.toString()); log.trace("takerSignature s " + takerSignature.s.toString());
@ -500,7 +500,7 @@ public class TradeWalletService {
Sha256Hash hashForSignature = payoutTx.hashForSignature(0, redeemScript.getProgram(), (byte) 1); Sha256Hash hashForSignature = payoutTx.hashForSignature(0, redeemScript.getProgram(), (byte) 1);
log.trace("hashForSignature " + Utils.HEX.encode(hashForSignature.getBytes())); log.trace("hashForSignature " + Utils.HEX.encode(hashForSignature.getBytes()));
TransactionSignature offererTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(offererSignature), TransactionSignature offererTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(buyerSignature),
Transaction.SigHash.ALL, false); Transaction.SigHash.ALL, false);
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false); TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
// Take care of order of signatures. See comment below at getMultiSigRedeemScript // Take care of order of signatures. See comment below at getMultiSigRedeemScript

View file

@ -61,7 +61,19 @@ public class TaskRunner<T extends Model> {
try { try {
currentTask = tasks.poll(); currentTask = tasks.poll();
log.trace("Run task: " + currentTask.getSimpleName()); log.trace("Run task: " + currentTask.getSimpleName());
log.debug("sharedModel.getClass() " + sharedModel.getClass());
log.debug("sharedModel.getClass().getSuperclass() " + sharedModel.getClass().getSuperclass());
/* Object c = currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass());
log.debug("c " + c);
Object c2 = currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass().getSuperclass());
log.debug("c getSuperclass " + c2);
Object o = currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass()).newInstance(this, sharedModel);*/
//TODO solve in tasks problem with superclasses
try {
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass()).newInstance(this, sharedModel).run(); currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass()).newInstance(this, sharedModel).run();
} catch (Throwable throwable) {
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass().getSuperclass()).newInstance(this, sharedModel).run();
}
} catch (Throwable throwable) { } catch (Throwable throwable) {
throwable.printStackTrace(); throwable.printStackTrace();
handleErrorMessage("Error at taskRunner: " + throwable.getMessage()); handleErrorMessage("Error at taskRunner: " + throwable.getMessage());

View file

@ -22,6 +22,7 @@ lower gradient color on tab: dddddd
.root { .root {
-bs-grey: #666666; -bs-grey: #666666;
-bs-bg-grey: #dddddd; -bs-bg-grey: #dddddd;
-bs-bg-green: #00aa33;
-bs-error-red: #dd0000; -bs-error-red: #dd0000;
-fx-accent: #0f87c3; -fx-accent: #0f87c3;
@ -466,6 +467,42 @@ textfield */
-fx-background-radius: 3px, 3px, 2px, 1px; -fx-background-radius: 3px, 3px, 2px, 1px;
} }
/* Pending trades */
#trade-wizard-item-background-disabled {
-fx-body-color: linear-gradient(to bottom, #f4f4f4, #F0F0F0);
-fx-outer-border: linear-gradient(to bottom, #dddddd, #ccc);
-fx-background-color: -fx-shadow-highlight-color,
-fx-outer-border,
-fx-inner-border,
-fx-body-color;
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
-fx-background-radius: 3px, 3px, 2px, 1px;
}
#trade-wizard-item-background-active {
-fx-body-color: linear-gradient(to bottom, #f1f6f7, #e7f5f9);
-fx-outer-border: linear-gradient(to bottom, #b5e1ef, #6aa4b6);
-fx-background-color: -fx-shadow-highlight-color,
-fx-outer-border,
-fx-inner-border,
-fx-body-color;
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
-fx-background-radius: 3px, 3px, 2px, 1px;
}
#trade-wizard-item-background-completed{
-fx-body-color: linear-gradient(to bottom, #f4f4f4, #E1E9E1);
-fx-outer-border: linear-gradient(to bottom, #99ba9c, #619865);
-fx-background-color: -fx-shadow-highlight-color,
-fx-outer-border,
-fx-inner-border,
-fx-body-color;
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
-fx-background-radius: 3px, 3px, 2px, 1px;
}
/* TitledGroupBg */ /* TitledGroupBg */
#titled-group-bg-label { #titled-group-bg-label {
-fx-font-weight: bold; -fx-font-weight: bold;

View file

@ -91,9 +91,9 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
setDisable(true); // alpha setDisable(true); // alpha
}}; }};
ToggleButton settingsButton = new NavButton(SettingsView.class, "Settings"); ToggleButton settingsButton = new NavButton(SettingsView.class, "Settings");
ToggleButton accountButton = new NavButton(AccountView.class, "Account") {{ ToggleButton accountButton = new NavButton(AccountView.class, "Account"); /*{{
setDisable(true); // alpha setDisable(true); // alpha
}}; }};*/
Pane portfolioButtonHolder = new Pane(portfolioButton); Pane portfolioButtonHolder = new Pane(portfolioButton);
Pane bankAccountComboBoxHolder = new Pane(); Pane bankAccountComboBoxHolder = new Pane();

View file

@ -118,7 +118,7 @@ public class AccountView extends ActivatableView<TabPane, AccountViewModel> {
} }
// for IRC demo we deactivate the arbitratorSettingsTab // for IRC demo we deactivate the arbitratorSettingsTab
arbitratorSettingsTab.setDisable(true); // arbitratorSettingsTab.setDisable(true);
tab.setContent(view.getRoot()); tab.setContent(view.getRoot());
root.getSelectionModel().select(tab); root.getSelectionModel().select(tab);

View file

@ -28,6 +28,7 @@ import javax.inject.Inject;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.*; import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.stage.Modality; import javafx.stage.Modality;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -69,6 +70,10 @@ public class ArbitratorSettingsView extends AbstractView {
stage.initOwner(primaryStage); stage.initOwner(primaryStage);
Scene scene = new Scene((Parent) view.getRoot(), 800, 600); Scene scene = new Scene((Parent) view.getRoot(), 800, 600);
stage.setScene(scene); stage.setScene(scene);
stage.setOnCloseRequest(e -> {
// need to unset root to be re-uasabel to other popups screens
scene.setRoot(new Pane());
});
stage.show(); stage.show();
} }
} }

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.account.content.irc; package io.bitsquare.gui.main.account.content.altcoin;
import io.bitsquare.common.viewfx.model.Activatable; import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel; import io.bitsquare.common.viewfx.model.DataModel;
@ -33,7 +33,7 @@ import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
class IrcAccountDataModel implements Activatable, DataModel { class AltCoinAccountDataModel implements Activatable, DataModel {
private final User user; private final User user;
@ -48,7 +48,7 @@ class IrcAccountDataModel implements Activatable, DataModel {
@Inject @Inject
public IrcAccountDataModel(User user) { public AltCoinAccountDataModel(User user) {
this.user = user; this.user = user;
} }

View file

@ -24,7 +24,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<GridPane fx:id="root" fx:controller="io.bitsquare.gui.main.account.content.irc.IrcAccountView" hgap="5.0" <GridPane fx:id="root" fx:controller="io.bitsquare.gui.main.account.content.altcoin.AltCoinAccountView" hgap="5.0"
vgap="5.0" vgap="5.0"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.account.content.irc; package io.bitsquare.gui.main.account.content.altcoin;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel; import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.FxmlView; import io.bitsquare.common.viewfx.view.FxmlView;
@ -40,7 +40,7 @@ import javafx.util.Callback;
* Just temporary for giving the user a possibility to test the app via simulating the bank transfer in a IRC chat. * Just temporary for giving the user a possibility to test the app via simulating the bank transfer in a IRC chat.
*/ */
@FxmlView @FxmlView
public class IrcAccountView extends ActivatableViewAndModel<GridPane, IrcAccountViewModel> implements Wizard.Step { public class AltCoinAccountView extends ActivatableViewAndModel<GridPane, AltCoinAccountViewModel> implements Wizard.Step {
@FXML HBox buttonsHBox; @FXML HBox buttonsHBox;
@FXML InputTextField ircNickNameTextField; @FXML InputTextField ircNickNameTextField;
@ -51,7 +51,7 @@ public class IrcAccountView extends ActivatableViewAndModel<GridPane, IrcAccount
private Wizard wizard; private Wizard wizard;
@Inject @Inject
public IrcAccountView(IrcAccountViewModel model) { public AltCoinAccountView(AltCoinAccountViewModel model) {
super(model); super(model);
} }

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.account.content.irc; package io.bitsquare.gui.main.account.content.altcoin;
import io.bitsquare.common.viewfx.model.ActivatableWithDataModel; import io.bitsquare.common.viewfx.model.ActivatableWithDataModel;
import io.bitsquare.common.viewfx.model.ViewModel; import io.bitsquare.common.viewfx.model.ViewModel;
@ -36,7 +36,7 @@ import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.util.StringConverter; import javafx.util.StringConverter;
class IrcAccountViewModel extends ActivatableWithDataModel<IrcAccountDataModel> implements ViewModel { class AltCoinAccountViewModel extends ActivatableWithDataModel<AltCoinAccountDataModel> implements ViewModel {
private final InputValidator nickNameValidator; private final InputValidator nickNameValidator;
@ -46,7 +46,7 @@ class IrcAccountViewModel extends ActivatableWithDataModel<IrcAccountDataModel>
final ObjectProperty<FiatAccount.Type> type = new SimpleObjectProperty<>(); final ObjectProperty<FiatAccount.Type> type = new SimpleObjectProperty<>();
@Inject @Inject
public IrcAccountViewModel(IrcAccountDataModel dataModel, BankAccountNumberValidator nickNameValidator) { public AltCoinAccountViewModel(AltCoinAccountDataModel dataModel, BankAccountNumberValidator nickNameValidator) {
super(dataModel); super(dataModel);
this.nickNameValidator = nickNameValidator; this.nickNameValidator = nickNameValidator;

View file

@ -17,7 +17,6 @@
package io.bitsquare.gui.main.account.settings; package io.bitsquare.gui.main.account.settings;
import io.bitsquare.BitsquareException;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel; import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.CachingViewLoader; import io.bitsquare.common.viewfx.view.CachingViewLoader;
import io.bitsquare.common.viewfx.view.FxmlView; import io.bitsquare.common.viewfx.view.FxmlView;
@ -29,7 +28,7 @@ import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.account.AccountView; import io.bitsquare.gui.main.account.AccountView;
import io.bitsquare.gui.main.account.content.changepassword.ChangePasswordView; import io.bitsquare.gui.main.account.content.changepassword.ChangePasswordView;
import io.bitsquare.gui.main.account.content.irc.IrcAccountView; import io.bitsquare.gui.main.account.content.fiat.FiatAccountView;
import io.bitsquare.gui.main.account.content.registration.RegistrationView; import io.bitsquare.gui.main.account.content.registration.RegistrationView;
import io.bitsquare.gui.main.account.content.restrictions.RestrictionsView; import io.bitsquare.gui.main.account.content.restrictions.RestrictionsView;
import io.bitsquare.gui.main.account.content.seedwords.SeedWordsView; import io.bitsquare.gui.main.account.content.seedwords.SeedWordsView;
@ -52,7 +51,7 @@ public class AccountSettingsView extends ActivatableViewAndModel {
private final ViewLoader viewLoader; private final ViewLoader viewLoader;
private final Navigation navigation; private final Navigation navigation;
private MenuItem seedWords, password, restrictions, ircAccount, registration; private MenuItem seedWords, password, restrictions, fiatAccount, registration;
private Navigation.Listener listener; private Navigation.Listener listener;
@FXML private VBox leftVBox; @FXML private VBox leftVBox;
@ -77,15 +76,10 @@ public class AccountSettingsView extends ActivatableViewAndModel {
seedWords = new MenuItem(navigation, toggleGroup, "Wallet seed", SeedWordsView.class); seedWords = new MenuItem(navigation, toggleGroup, "Wallet seed", SeedWordsView.class);
password = new MenuItem(navigation, toggleGroup, "Wallet password", ChangePasswordView.class); password = new MenuItem(navigation, toggleGroup, "Wallet password", ChangePasswordView.class);
restrictions = new MenuItem(navigation, toggleGroup, "Arbitrator selection", RestrictionsView.class); restrictions = new MenuItem(navigation, toggleGroup, "Arbitrator selection", RestrictionsView.class);
ircAccount = new MenuItem(navigation, toggleGroup, "Payments account(s)", IrcAccountView.class); fiatAccount = new MenuItem(navigation, toggleGroup, "Payments account(s)", FiatAccountView.class);
registration = new MenuItem(navigation, toggleGroup, "Renew your account", RegistrationView.class); registration = new MenuItem(navigation, toggleGroup, "Renew your account", RegistrationView.class);
seedWords.setDisable(true); leftVBox.getChildren().addAll(seedWords, password, restrictions, fiatAccount, registration);
password.setDisable(true);
restrictions.setDisable(true);
registration.setDisable(true);
leftVBox.getChildren().addAll(seedWords, password, restrictions, ircAccount, registration);
} }
@Override @Override
@ -93,7 +87,7 @@ public class AccountSettingsView extends ActivatableViewAndModel {
navigation.addListener(listener); navigation.addListener(listener);
ViewPath viewPath = navigation.getCurrentPath(); ViewPath viewPath = navigation.getCurrentPath();
if (viewPath.size() == 3 && viewPath.indexOf(AccountSettingsView.class) == 2) { if (viewPath.size() == 3 && viewPath.indexOf(AccountSettingsView.class) == 2) {
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, IrcAccountView.class); navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, SeedWordsView.class);
} }
else if (viewPath.size() == 4 && viewPath.indexOf(AccountSettingsView.class) == 2) { else if (viewPath.size() == 4 && viewPath.indexOf(AccountSettingsView.class) == 2) {
loadView(viewPath.get(3)); loadView(viewPath.get(3));
@ -114,9 +108,8 @@ public class AccountSettingsView extends ActivatableViewAndModel {
if (view instanceof SeedWordsView) seedWords.setSelected(true); if (view instanceof SeedWordsView) seedWords.setSelected(true);
else if (view instanceof ChangePasswordView) password.setSelected(true); else if (view instanceof ChangePasswordView) password.setSelected(true);
else if (view instanceof RestrictionsView) restrictions.setSelected(true); else if (view instanceof RestrictionsView) restrictions.setSelected(true);
else if (view instanceof IrcAccountView) ircAccount.setSelected(true); else if (view instanceof FiatAccountView) fiatAccount.setSelected(true);
else if (view instanceof RegistrationView) registration.setSelected(true); else if (view instanceof RegistrationView) registration.setSelected(true);
else throw new BitsquareException("Selecting main menu button for view " + view + " is not supported");
} }
} }

View file

@ -25,7 +25,7 @@ import io.bitsquare.common.viewfx.view.ViewLoader;
import io.bitsquare.common.viewfx.view.Wizard; import io.bitsquare.common.viewfx.view.Wizard;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.account.content.irc.IrcAccountView; import io.bitsquare.gui.main.account.content.fiat.FiatAccountView;
import io.bitsquare.gui.main.account.content.password.PasswordView; import io.bitsquare.gui.main.account.content.password.PasswordView;
import io.bitsquare.gui.main.account.content.registration.RegistrationView; import io.bitsquare.gui.main.account.content.registration.RegistrationView;
import io.bitsquare.gui.main.account.content.restrictions.RestrictionsView; import io.bitsquare.gui.main.account.content.restrictions.RestrictionsView;
@ -46,7 +46,7 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
@FXML VBox leftVBox; @FXML VBox leftVBox;
@FXML AnchorPane content; @FXML AnchorPane content;
private WizardItem seedWords, password, ircAccount, restrictions, registration; private WizardItem seedWords, password, fiatAccount, restrictions, registration;
private Navigation.Listener listener; private Navigation.Listener listener;
private final ViewLoader viewLoader; private final ViewLoader viewLoader;
@ -78,17 +78,17 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
password.onCompleted(); password.onCompleted();
restrictions.show(); restrictions.show();
} }
else if (viewClass == IrcAccountView.class) { else if (viewClass == FiatAccountView.class) {
seedWords.onCompleted(); seedWords.onCompleted();
password.onCompleted(); password.onCompleted();
restrictions.onCompleted(); restrictions.onCompleted();
ircAccount.show(); fiatAccount.show();
} }
else if (viewClass == RegistrationView.class) { else if (viewClass == RegistrationView.class) {
seedWords.onCompleted(); seedWords.onCompleted();
password.onCompleted(); password.onCompleted();
restrictions.onCompleted(); restrictions.onCompleted();
ircAccount.onCompleted(); fiatAccount.onCompleted();
registration.show(); registration.show();
} }
}; };
@ -99,23 +99,18 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
"Setup password", "Protect your wallet with a password"); "Setup password", "Protect your wallet with a password");
restrictions = new WizardItem(RestrictionsView.class, restrictions = new WizardItem(RestrictionsView.class,
"Select arbitrators", "Select which arbitrators you want to use for trading"); "Select arbitrators", "Select which arbitrators you want to use for trading");
ircAccount = new WizardItem(IrcAccountView.class, fiatAccount = new WizardItem(FiatAccountView.class,
" Setup Payments account(s)", "You need to setup at least one payment account"); " Setup Payments account(s)", "You need to setup at least one payment account");
registration = new WizardItem(RegistrationView.class, registration = new WizardItem(RegistrationView.class,
"Register your account", "The registration in the Blockchain requires a payment of 0.0002 BTC"); "Register your account", "The registration in the Blockchain requires a payment of 0.0002 BTC");
leftVBox.getChildren().addAll(seedWords, password, restrictions, ircAccount, registration); leftVBox.getChildren().addAll(seedWords, password, restrictions, fiatAccount, registration);
seedWords.setDisable(true);
password.setDisable(true);
restrictions.setDisable(true);
registration.setDisable(true);
} }
@Override @Override
public void activate() { public void activate() {
navigation.addListener(listener); navigation.addListener(listener);
ircAccount.show(); seedWords.show();
} }
@Override @Override
@ -135,10 +130,10 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
} }
else if (currentStep instanceof RestrictionsView) { else if (currentStep instanceof RestrictionsView) {
restrictions.onCompleted(); restrictions.onCompleted();
ircAccount.show(); fiatAccount.show();
} }
else if (currentStep instanceof IrcAccountView) { else if (currentStep instanceof FiatAccountView) {
ircAccount.onCompleted(); fiatAccount.onCompleted();
registration.show(); registration.show();
} }
else if (currentStep instanceof RegistrationView) { else if (currentStep instanceof RegistrationView) {

View file

@ -28,31 +28,31 @@ import io.bitsquare.trade.protocol.placeoffer.tasks.AddOfferToRemoteOfferBook;
import io.bitsquare.trade.protocol.placeoffer.tasks.BroadcastCreateOfferFeeTx; import io.bitsquare.trade.protocol.placeoffer.tasks.BroadcastCreateOfferFeeTx;
import io.bitsquare.trade.protocol.placeoffer.tasks.CreateOfferFeeTx; import io.bitsquare.trade.protocol.placeoffer.tasks.CreateOfferFeeTx;
import io.bitsquare.trade.protocol.placeoffer.tasks.ValidateOffer; import io.bitsquare.trade.protocol.placeoffer.tasks.ValidateOffer;
import io.bitsquare.trade.protocol.trade.offerer.OffererProtocol; import io.bitsquare.trade.protocol.trade.offerer.OffererAsBuyerProtocol;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateAndSignPayoutTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateOffererDepositTxInputs; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendRequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsRequestSellerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendFiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSignsAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererVerifiesAndSignsContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.TakerProtocol; import io.bitsquare.trade.protocol.trade.taker.TakerAsSellerProtocol;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessFiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessRequestSellerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSignsAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CommitDepositTx; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignDepositTx; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment; import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount; import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount;
@ -100,44 +100,44 @@ public class DebugView extends InitializableView {
/*---- Protocol ----*/ /*---- Protocol ----*/
OffererProtocol.class, OffererAsBuyerProtocol.class,
ProcessRequestDepositTxInputsMessage.class, OffererProcessRequestDepositTxInputsMessage.class,
CreateOffererDepositTxInputs.class, OffererCreatesDepositTxInputs.class,
SendRequestTakerDepositPaymentMessage.class, OffererSendsRequestSellerDepositPaymentMessage.class,
ProcessRequestPublishDepositTxMessage.class, OffererProcessRequestPublishDepositTxMessage.class,
VerifyTakerAccount.class, VerifyTakerAccount.class,
VerifyAndSignContract.class, OffererVerifiesAndSignsContract.class,
SignAndPublishDepositTx.class, OffererSignsAndPublishDepositTx.class,
SendDepositTxPublishedMessage.class, OffererSendsDepositTxPublishedMessage.class,
CreateAndSignPayoutTx.class, OffererCreatesAndSignPayoutTx.class,
VerifyTakeOfferFeePayment.class, VerifyTakeOfferFeePayment.class,
SendFiatTransferStartedMessage.class, OffererSendsFiatTransferStartedMessage.class,
ProcessPayoutTxPublishedMessage.class, OffererProcessPayoutTxPublishedMessage.class,
Boolean.class, /* used as seperator*/ Boolean.class, /* used as seperator*/
/*---- Protocol ----*/ /*---- Protocol ----*/
TakerProtocol.class, TakerAsSellerProtocol.class,
CreateTakeOfferFeeTx.class, CreateTakeOfferFeeTx.class,
SendRequestDepositTxInputsMessage.class, TakerSendsRequestDepositTxInputsMessage.class,
ProcessRequestTakerDepositPaymentMessage.class, TakerProcessRequestSellerDepositPaymentMessage.class,
VerifyOffererAccount.class, VerifyOffererAccount.class,
CreateAndSignContract.class, TakerCreatesAndSignContract.class,
CreateAndSignDepositTx.class, TakerCreatesAndSignsDepositTx.class,
SendRequestPublishDepositTxMessage.class, TakerSendsRequestPublishDepositTxMessage.class,
ProcessDepositTxPublishedMessage.class, TakerProcessDepositTxPublishedMessage.class,
CommitDepositTx.class, TakerCommitDepositTx.class,
ProcessFiatTransferStartedMessage.class, TakerProcessFiatTransferStartedMessage.class,
SignAndPublishPayoutTx.class, TakerSignsAndPublishPayoutTx.class,
VerifyOfferFeePayment.class, VerifyOfferFeePayment.class,
SendPayoutTxPublishedMessage.class TakerSendsPayoutTxPublishedMessage.class
) )
); );

View file

@ -20,8 +20,8 @@ package io.bitsquare.gui.main.portfolio.closed;
import io.bitsquare.common.viewfx.model.ActivatableWithDataModel; import io.bitsquare.common.viewfx.model.ActivatableWithDataModel;
import io.bitsquare.common.viewfx.model.ViewModel; import io.bitsquare.common.viewfx.model.ViewModel;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -71,8 +71,8 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
String getState(ClosedTradesListItem item) { String getState(ClosedTradesListItem item) {
if (item != null && item.getTrade() != null) { if (item != null && item.getTrade() != null) {
Trade.LifeCycleState lifeCycleState = item.getTrade().lifeCycleStateProperty().get(); Trade.LifeCycleState lifeCycleState = item.getTrade().lifeCycleStateProperty().get();
if (lifeCycleState instanceof TakerTrade.TakerLifeCycleState) { if (lifeCycleState instanceof TakerAsBuyerTrade.LifeCycleState) {
switch ((TakerTrade.TakerLifeCycleState) lifeCycleState) { switch ((TakerAsBuyerTrade.LifeCycleState) lifeCycleState) {
case COMPLETED: case COMPLETED:
return "Completed"; return "Completed";
case FAILED: case FAILED:
@ -81,8 +81,8 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list."); throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
} }
} }
else if (lifeCycleState instanceof OffererTrade.OffererLifeCycleState) { else if (lifeCycleState instanceof OffererAsSellerTrade.LifeCycleState) {
switch ((OffererTrade.OffererLifeCycleState) lifeCycleState) { switch ((OffererAsSellerTrade.LifeCycleState) lifeCycleState) {
case OFFER_CANCELED: case OFFER_CANCELED:
return "Canceled"; return "Canceled";
case COMPLETED: case COMPLETED:
@ -94,11 +94,7 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list."); throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
} }
} }
throw new RuntimeException("That must not happen. We got no defined state.");
} }
else {
return ""; return "";
} }
} }
}

View file

@ -23,7 +23,9 @@ import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel; import io.bitsquare.common.viewfx.model.DataModel;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
@ -35,6 +37,8 @@ import com.google.inject.Inject;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
@ -65,8 +69,8 @@ class PendingTradesDataModel implements Activatable, DataModel {
final StringProperty txId = new SimpleStringProperty(); final StringProperty txId = new SimpleStringProperty();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1); final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<TakerTrade.TakerProcessState> takerProcessState = new SimpleObjectProperty<>(); final ObjectProperty<Trade.ProcessState> takerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<OffererTrade.OffererProcessState> offererProcessState = new SimpleObjectProperty<>(); final ObjectProperty<Trade.ProcessState> offererProcessState = new SimpleObjectProperty<>();
@Inject @Inject
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) { public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) {
@ -115,10 +119,10 @@ class PendingTradesDataModel implements Activatable, DataModel {
isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey()); isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
Trade trade = getTrade(); Trade trade = getTrade();
if (trade instanceof TakerTrade) if (trade instanceof TakerAsSellerTrade)
takerProcessState.bind(((TakerTrade) trade).processStateProperty()); takerProcessState.bind(trade.processStateProperty());
else else
offererProcessState.bind(((OffererTrade) trade).processStateProperty()); offererProcessState.bind(trade.processStateProperty());
log.trace("selectTrade trade.stateProperty().get() " + trade.processStateProperty().get()); log.trace("selectTrade trade.stateProperty().get() " + trade.processStateProperty().get());
@ -127,11 +131,11 @@ class PendingTradesDataModel implements Activatable, DataModel {
} }
void fiatPaymentStarted() { void fiatPaymentStarted() {
((OffererTrade) getTrade()).onFiatPaymentStarted(); ((OffererAsBuyerTrade) getTrade()).onFiatPaymentStarted();
} }
void fiatPaymentReceived() { void fiatPaymentReceived() {
((TakerTrade) getTrade()).onFiatPaymentReceived(); ((TakerAsSellerTrade) getTrade()).onFiatPaymentReceived();
} }
void withdraw(String toAddress) { void withdraw(String toAddress) {
@ -180,8 +184,9 @@ class PendingTradesDataModel implements Activatable, DataModel {
return isOfferer; return isOfferer;
} }
@Nullable
Trade getTrade() { Trade getTrade() {
return selectedItem.getTrade(); return selectedItem != null ? selectedItem.getTrade() : null;
} }
Coin getTotalFees() { Coin getTotalFees() {

View file

@ -17,6 +17,8 @@
package io.bitsquare.gui.main.portfolio.pending; package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -51,11 +53,17 @@ public class PendingTradesListItem {
} }
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() { public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return trade.tradeAmountProperty(); if (trade instanceof TakerTrade)
return ((TakerTrade) trade).tradeAmountProperty();
else
return ((OffererTrade) trade).tradeAmountProperty();
} }
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() { public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return trade.tradeVolumeProperty(); if (trade instanceof TakerTrade)
return ((TakerTrade) trade).tradeVolumeProperty();
else
return ((OffererTrade) trade).tradeVolumeProperty();
} }
public Date getDate() { public Date getDate() {

View file

@ -0,0 +1,75 @@
/*
* 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.gui.main.portfolio.pending;
import io.bitsquare.gui.main.portfolio.pending.steps.CompletedView;
import io.bitsquare.gui.main.portfolio.pending.steps.StartFiatView;
import io.bitsquare.gui.main.portfolio.pending.steps.WaitView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PendingTradesOffererAsBuyerView extends PendingTradesStepsView {
private static final Logger log = LoggerFactory.getLogger(PendingTradesOffererAsBuyerView.class);
private TradeWizardItem waitTxConfirm;
private TradeWizardItem startFiat;
private TradeWizardItem waitFiatReceived;
private TradeWizardItem completed;
public PendingTradesOffererAsBuyerView() {
super();
}
public void activate() {
showWaitTxConfirm();
}
public void deactivate() {
}
public void showWaitTxConfirm() {
showItem(waitTxConfirm);
}
public void showStartFiat() {
showItem(startFiat);
}
public void showWaitFiatReceived() {
showItem(waitFiatReceived);
}
public void showCompleted() {
showItem(completed);
}
@Override
protected void addWizards() {
waitTxConfirm = new TradeWizardItem(WaitView.class, "Wait for blockchain confirmation");
startFiat = new TradeWizardItem(StartFiatView.class, "Start payment");
waitFiatReceived = new TradeWizardItem(WaitView.class, "Wait until payment has arrived");
completed = new TradeWizardItem(CompletedView.class, "Completed");
leftVBox.getChildren().addAll(waitTxConfirm, startFiat, waitFiatReceived, completed);
}
}

View file

@ -0,0 +1,91 @@
/*
* 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.gui.main.portfolio.pending;
import io.bitsquare.gui.util.Layout;
import javafx.scene.*;
import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class PendingTradesStepsView extends HBox {
private static final Logger log = LoggerFactory.getLogger(PendingTradesStepsView.class);
protected VBox leftVBox;
protected AnchorPane contentPane;
protected TradeWizardItem current;
public PendingTradesStepsView() {
setSpacing(Layout.PADDING_WINDOW);
buildViews();
}
public void activate() {
}
public void deactivate() {
}
protected void buildViews() {
addLeftBox();
addContentPane();
addWizards();
activate();
}
abstract protected void addWizards();
protected void showItem(TradeWizardItem item) {
if (current != null)
current.onCompleted();
current = item;
current.show();
loadView(item.getViewClass());
}
protected void loadView(Class<? extends Node> viewClass) {
Node view = null;
try {
view = viewClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
contentPane.getChildren().setAll(view);
}
private void addLeftBox() {
leftVBox = new VBox();
leftVBox.setSpacing(Layout.SPACING_VBOX);
getChildren().add(leftVBox);
}
private void addContentPane() {
contentPane = new AnchorPane();
HBox.setHgrow(contentPane, Priority.SOMETIMES);
getChildren().add(contentPane);
}
}

View file

@ -23,8 +23,10 @@ import io.bitsquare.common.viewfx.model.ViewModel;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.validation.BtcAddressValidator; import io.bitsquare.gui.util.validation.BtcAddressValidator;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
@ -240,7 +242,50 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
} }
private void updateTakerState() { private void updateTakerState() {
TakerTrade.TakerProcessState processState = dataModel.takerProcessState.get(); if (dataModel.getTrade() instanceof TakerAsSellerTrade) {
TakerAsSellerTrade.ProcessState processState = (TakerAsSellerTrade.ProcessState) dataModel.takerProcessState.get();
log.debug("updateTakerState " + processState);
if (processState != null) {
switch (processState) {
case TAKE_OFFER_FEE_TX_CREATED:
break;
case TAKE_OFFER_FEE_PUBLISHED:
break;
case TAKE_OFFER_FEE_PUBLISH_FAILED:
break;
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.TAKER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case FIAT_PAYMENT_RECEIVED:
viewState.set(ViewState.TAKER_SELLER_COMPLETED);
break;
case PAYOUT_PUBLISHED:
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled processState " + processState);
break;
}
}
}
else if (dataModel.getTrade() instanceof TakerAsBuyerTrade) {
TakerAsBuyerTrade.ProcessState processState = (TakerAsBuyerTrade.ProcessState) dataModel.takerProcessState.get();
log.debug("updateTakerState " + processState); log.debug("updateTakerState " + processState);
if (processState != null) { if (processState != null) {
switch (processState) { switch (processState) {
@ -282,8 +327,11 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
} }
} }
}
private void updateOffererState() { private void updateOffererState() {
OffererTrade.OffererProcessState processState = dataModel.offererProcessState.get(); if (dataModel.getTrade() instanceof OffererAsBuyerTrade) {
OffererAsBuyerTrade.ProcessState processState = (OffererAsBuyerTrade.ProcessState) dataModel.offererProcessState.get();
log.debug("updateOffererState " + processState); log.debug("updateOffererState " + processState);
if (processState != null) { if (processState != null) {
switch (processState) { switch (processState) {
@ -315,4 +363,39 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
} }
} }
} }
else if (dataModel.getTrade() instanceof OffererAsSellerTrade) {
OffererAsSellerTrade.ProcessState processState = (OffererAsSellerTrade.ProcessState) dataModel.offererProcessState.get();
log.debug("updateOffererState " + processState);
if (processState != null) {
switch (processState) {
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.OFFERER_BUYER_START_PAYMENT);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
break;
case PAYOUT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled viewState " + processState);
break;
}
}
}
}
} }

View file

@ -0,0 +1,68 @@
/*
* 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.gui.main.portfolio.pending;
import io.bitsquare.gui.util.Colors;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
public class TradeWizardItem extends Button {
public Class<? extends Node> getViewClass() {
return viewClass;
}
private final Class<? extends Node> viewClass;
public TradeWizardItem(Class<? extends Node> viewClass, String title) {
this.viewClass = viewClass;
setText(title);
setId("trade-wizard-item-background-disabled");
setPrefHeight(40);
setPrefWidth(270);
setPadding(new Insets(0, 20, 0, 10));
setAlignment(Pos.CENTER_LEFT);
Label icon = new Label();
icon.setTextFill(Colors.MID_GREY);
AwesomeDude.setIcon(icon, AwesomeIcon.ANGLE_DOWN);
setGraphic(icon);
}
void show() {
setId("trade-wizard-item-background-active");
Label icon = new Label();
icon.setTextFill(Colors.BLUE);
AwesomeDude.setIcon(icon, AwesomeIcon.ARROW_RIGHT);
setGraphic(icon);
}
void onCompleted() {
setId("trade-wizard-item-background-completed");
Label icon = new Label();
icon.setTextFill(Colors.GREEN);
AwesomeDude.setIcon(icon, AwesomeIcon.OK);
setGraphic(icon);
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.gui.main.portfolio.pending.proto;
import io.bitsquare.gui.main.portfolio.pending.PendingTradesOffererAsBuyerView;
import io.bitsquare.gui.util.Layout;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PendingMain extends Application {
private static final Logger log = LoggerFactory.getLogger(PendingMain.class);
@Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
PendingTradesOffererAsBuyerView pendingTradesOffererAsBuyerView = new PendingTradesOffererAsBuyerView();
AnchorPane.setLeftAnchor(pendingTradesOffererAsBuyerView, Layout.PADDING_WINDOW);
AnchorPane.setRightAnchor(pendingTradesOffererAsBuyerView, Layout.PADDING_WINDOW);
AnchorPane.setTopAnchor(pendingTradesOffererAsBuyerView, Layout.PADDING_WINDOW);
AnchorPane.setBottomAnchor(pendingTradesOffererAsBuyerView, Layout.PADDING_WINDOW);
root.getChildren().add(pendingTradesOffererAsBuyerView);
Scene scene = new Scene(root, 1000, 600);
scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css",
"/io/bitsquare/gui/images.css");
primaryStage.setScene(scene);
primaryStage.show();
}
}

View file

@ -0,0 +1,95 @@
/*
* 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.gui.main.portfolio.pending.steps;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.Layout;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.ComponentBuilder.*;
public class CompletedView extends AnchorPane{
private static final Logger log = LoggerFactory.getLogger(WaitView.class);
private Label btcTradeAmountLabel;
private TextField btcTradeAmountTextField;
private Label fiatTradeAmountLabel;
private TextField fiatTradeAmountTextField;
private Label feesLabel;
private TextField feesTextField;
private Label securityDepositLabel;
private TextField securityDepositTextField;
private InfoDisplay infoDisplay;
private InputTextField withdrawAddressTextField;
private TextField withdrawAmountTextField;
public CompletedView() {
buildViews();
}
private void buildViews() {
AnchorPane.setLeftAnchor(this, 0d);
AnchorPane.setRightAnchor(this, 0d);
AnchorPane.setTopAnchor(this, 0d);
AnchorPane.setBottomAnchor(this, 0d);
int i = 0;
GridPane gridPane = getAndAddGridPane(this);
getAndAddTitledGroupBg(gridPane, i, 5, "Summary");
LabelTextFieldPair btcTradeAmountPair = getAndAddLabelTextFieldPair(gridPane, i++, "You have bought:", Layout.FIRST_ROW_DISTANCE);
btcTradeAmountLabel = btcTradeAmountPair.label;
btcTradeAmountTextField = btcTradeAmountPair.textField;
LabelTextFieldPair fiatTradeAmountPair = getAndAddLabelTextFieldPair(gridPane, i++, "You have paid:");
fiatTradeAmountLabel = fiatTradeAmountPair.label;
fiatTradeAmountTextField = fiatTradeAmountPair.textField;
LabelTextFieldPair feesPair = getAndAddLabelTextFieldPair(gridPane, i++, "Total fees paid:");
feesLabel = feesPair.label;
feesTextField = feesPair.textField;
LabelTextFieldPair securityDepositPair = getAndAddLabelTextFieldPair(gridPane, i++, "Refunded security deposit:");
securityDepositLabel = securityDepositPair.label;
securityDepositTextField = securityDepositPair.textField;
infoDisplay = getAndAddInfoDisplay(gridPane, i++, "infoDisplay", this::onOpenHelp);
getAndAddTitledGroupBg(gridPane, i, 2, "Withdraw your bitcoins", Layout.GROUP_DISTANCE);
withdrawAmountTextField = getAndAddLabelTextFieldPair(gridPane, i++, "Amount to withdraw:", Layout.FIRST_ROW_AND_GROUP_DISTANCE).textField;
withdrawAddressTextField = getAndAddLabelInputTextFieldPair(gridPane, i++, "Withdraw to address:").inputTextField;
getAndAddButton(gridPane, i++, "Withdraw to external wallet", this::onWithdraw);
}
private void onWithdraw(ActionEvent actionEvent) {
log.debug("onWithdraw");
}
private void onOpenHelp(ActionEvent actionEvent) {
log.debug("onOpenHelp");
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.gui.main.portfolio.pending.steps;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.TxIdTextField;
import io.bitsquare.gui.util.Layout;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.ComponentBuilder.*;
public class ConfirmFiatView extends AnchorPane {
private static final Logger log = LoggerFactory.getLogger(ConfirmFiatView.class);
private TextField statusTextField;
private TxIdTextField txIdTextField;
private InfoDisplay infoDisplay;
public ConfirmFiatView() {
buildViews();
}
private void buildViews() {
AnchorPane.setLeftAnchor(this, 0d);
AnchorPane.setRightAnchor(this, 0d);
AnchorPane.setTopAnchor(this, 0d);
AnchorPane.setBottomAnchor(this, 0d);
int i = 0;
GridPane gridPane = getAndAddGridPane(this);
getAndAddTitledGroupBg(gridPane, i, 3, "Trade status");
statusTextField = getAndAddLabelTextFieldPair(gridPane, i++, "Status:", Layout.FIRST_ROW_DISTANCE).textField;
txIdTextField = getAndAddLabelTxIdTextFieldPair(gridPane, i++, "Deposit transaction ID:").txIdTextField;
infoDisplay = getAndAddInfoDisplay(gridPane, i++, "infoDisplay", this::onOpenHelp);
getAndAddButton(gridPane, i++, "Confirm payment receipt", this::onPaymentReceived);
}
private void onPaymentReceived(ActionEvent actionEvent) {
log.debug("onPaymentReceived");
}
private void onOpenHelp(ActionEvent actionEvent) {
log.debug("onOpenHelp");
}
}

View file

@ -0,0 +1,73 @@
/*
* 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.gui.main.portfolio.pending.steps;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.TextFieldWithCopyIcon;
import io.bitsquare.gui.util.Layout;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.ComponentBuilder.*;
public class StartFiatView extends AnchorPane {
private static final Logger log = LoggerFactory.getLogger(WaitView.class);
private TextFieldWithCopyIcon fiatAmountTextField;
private TextField paymentMethodTextField;
private TextFieldWithCopyIcon holderNameTextField;
private TextFieldWithCopyIcon primarTextField;
private TextFieldWithCopyIcon secondaryIdTextField;
private InfoDisplay infoDisplay;
public StartFiatView() {
buildViews();
}
private void buildViews() {
AnchorPane.setLeftAnchor(this, 0d);
AnchorPane.setRightAnchor(this, 0d);
AnchorPane.setTopAnchor(this, 0d);
AnchorPane.setBottomAnchor(this, 0d);
int i = 0;
GridPane gridPane = getAndAddGridPane(this);
getAndAddTitledGroupBg(gridPane, i, 6, "Payments details");
fiatAmountTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, i++, "Amount to transfer:", Layout.FIRST_ROW_DISTANCE).textFieldWithCopyIcon;
paymentMethodTextField = getAndAddLabelTextFieldPair(gridPane, i++, "Payment method:").textField;
holderNameTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, i++, "Receiver:").textFieldWithCopyIcon;
primarTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, i++, "IBAN:").textFieldWithCopyIcon;
secondaryIdTextField = getAndAddLabelTextFieldWithCopyIconPair(gridPane, i++, "BIC:").textFieldWithCopyIcon;
infoDisplay = getAndAddInfoDisplay(gridPane, i++, "infoDisplay", this::onOpenHelp);
getAndAddButton(gridPane, i++, "Payment started", this::onPaymentStarted);
}
private void onPaymentStarted(ActionEvent actionEvent) {
log.debug("onPaymentStarted");
}
private void onOpenHelp(ActionEvent actionEvent) {
log.debug("onOpenHelp");
}
}

View file

@ -0,0 +1,64 @@
/*
* 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.gui.main.portfolio.pending.steps;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.TxIdTextField;
import io.bitsquare.gui.util.Layout;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.ComponentBuilder.*;
public class WaitView extends AnchorPane {
private static final Logger log = LoggerFactory.getLogger(WaitView.class);
private TextField statusTextField;
private TxIdTextField txIdTextField;
private InfoDisplay infoDisplay;
public WaitView() {
buildViews();
}
private void buildViews() {
AnchorPane.setLeftAnchor(this, 0d);
AnchorPane.setRightAnchor(this, 0d);
AnchorPane.setTopAnchor(this, 0d);
AnchorPane.setBottomAnchor(this, 0d);
int i = 0;
GridPane gridPane = getAndAddGridPane(this);
getAndAddTitledGroupBg(gridPane, i, 3, "Trade status");
statusTextField = getAndAddLabelTextFieldPair(gridPane, i++, "Status:", Layout.FIRST_ROW_DISTANCE).textField;
txIdTextField = getAndAddLabelTxIdTextFieldPair(gridPane, i++, "Deposit transaction ID:").txIdTextField;
infoDisplay = getAndAddInfoDisplay(gridPane, i++, "infoDisplay", this::onOpenHelp);
}
private void onOpenHelp(ActionEvent actionEvent) {
log.debug("onOpenHelp");
}
}

View file

@ -22,7 +22,6 @@ import io.bitsquare.common.viewfx.view.View;
import io.bitsquare.common.viewfx.view.ViewLoader; import io.bitsquare.common.viewfx.view.ViewLoader;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.components.InputTextField; import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.trade.createoffer.CreateOfferView; import io.bitsquare.gui.main.trade.createoffer.CreateOfferView;
import io.bitsquare.gui.main.trade.offerbook.OfferBookView; import io.bitsquare.gui.main.trade.offerbook.OfferBookView;
@ -128,13 +127,6 @@ public abstract class TradeView extends ActivatableView<TabPane, Void> {
OfferActionHandler offerActionHandler = new OfferActionHandler() { OfferActionHandler offerActionHandler = new OfferActionHandler() {
@Override @Override
public void createOffer(Coin amount, Fiat price) { public void createOffer(Coin amount, Fiat price) {
if (TradeView.this instanceof SellView) {
Popups.openWarningPopup("Warning",
"Please note that a sell offer is not supported yet for trading",
"You can create the offer and it appears in the offerbook, " +
"but nobody can take the offer.\n" +
"That will be implemented in an upcoming development milestone.");
}
TradeView.this.amount = amount; TradeView.this.amount = amount;
TradeView.this.price = price; TradeView.this.price = price;
TradeView.this.navigation.navigateTo(MainView.class, TradeView.this.getClass(), TradeView.this.navigation.navigateTo(MainView.class, TradeView.this.getClass(),
@ -175,7 +167,7 @@ public abstract class TradeView extends ActivatableView<TabPane, Void> {
// CreateOffer and TakeOffer must not be cached by ViewLoader as we cannot use a view multiple times // CreateOffer and TakeOffer must not be cached by ViewLoader as we cannot use a view multiple times
// in different graphs // in different graphs
takeOfferView = (TakeOfferView) view; takeOfferView = (TakeOfferView) view;
takeOfferView.initWithData(direction, amount, offer); takeOfferView.initWithData(amount, offer);
takeOfferPane = ((TakeOfferView) view).getRoot(); takeOfferPane = ((TakeOfferView) view).getRoot();
final Tab tab = new Tab("Take offer"); final Tab tab = new Tab("Take offer");
takeOfferView.setCloseHandler(() -> { takeOfferView.setCloseHandler(() -> {

View file

@ -75,7 +75,7 @@ class CreateOfferDataModel implements Activatable, DataModel {
private final String offerId; private final String offerId;
@Nullable private Offer.Direction direction = null; private Offer.Direction direction;
private AddressEntry addressEntry; private AddressEntry addressEntry;
final StringProperty requestPlaceOfferErrorMessage = new SimpleStringProperty(); final StringProperty requestPlaceOfferErrorMessage = new SimpleStringProperty();
@ -211,8 +211,12 @@ class CreateOfferDataModel implements Activatable, DataModel {
} }
void calculateTotalToPay() { void calculateTotalToPay() {
if (securityDepositAsCoin.get() != null) if (securityDepositAsCoin.get() != null) {
if (direction == Offer.Direction.BUY)
totalToPayAsCoin.set(offerFeeAsCoin.get().add(networkFeeAsCoin.get()).add(securityDepositAsCoin.get())); totalToPayAsCoin.set(offerFeeAsCoin.get().add(networkFeeAsCoin.get()).add(securityDepositAsCoin.get()));
else
totalToPayAsCoin.set(offerFeeAsCoin.get().add(networkFeeAsCoin.get()).add(securityDepositAsCoin.get()).add(amountAsCoin.get()));
}
} }
@ -234,13 +238,6 @@ class CreateOfferDataModel implements Activatable, DataModel {
return direction; return direction;
} }
@SuppressWarnings("NullableProblems")
void setDirection(Offer.Direction direction) {
// direction can not be changed once it is initially set
checkNotNull(direction);
this.direction = direction;
}
WalletService getWalletService() { WalletService getWalletService() {
return walletService; return walletService;
} }
@ -270,4 +267,9 @@ class CreateOfferDataModel implements Activatable, DataModel {
public Boolean getDisplaySecurityDepositInfo() { public Boolean getDisplaySecurityDepositInfo() {
return preferences.getDisplaySecurityDepositInfo(); return preferences.getDisplaySecurityDepositInfo();
} }
public void initWithData(Offer.Direction direction, Coin amount, Fiat price) {
checkNotNull(direction);
this.direction = direction;
}
} }

View file

@ -51,7 +51,7 @@
<Insets bottom="10.0" left="10.0" right="10.0" top="20.0"/> <Insets bottom="10.0" left="10.0" right="10.0" top="20.0"/>
</GridPane.margin> </GridPane.margin>
<ImageView fx:id="imageView" pickOnBounds="true"/> <ImageView fx:id="imageView" pickOnBounds="true"/>
<Label fx:id="buyLabel" id="direction-icon-label" text="%createOffer.amountPriceBox.subTitle" <Label fx:id="buyLabel" id="direction-icon-label"
alignment="CENTER"> alignment="CENTER">
<padding> <padding>
<Insets top="-5.0"/> <Insets top="-5.0"/>
@ -64,7 +64,7 @@
<Insets right="10.0" top="20.0"/> <Insets right="10.0" top="20.0"/>
</GridPane.margin> </GridPane.margin>
<VBox spacing="4"> <VBox spacing="4">
<Label id="input-description-label" text="%createOffer.amountPriceBox.amountDescription" <Label fx:id="amountToTradeLabel" id="input-description-label" text="%createOffer.amountPriceBox.amountDescription"
prefWidth="170"/> prefWidth="170"/>
<HBox> <HBox>
<InputTextField fx:id="amountTextField" id="text-input-with-currency-text-field" <InputTextField fx:id="amountTextField" id="text-input-with-currency-text-field"
@ -125,8 +125,7 @@
</HBox> </HBox>
</VBox> </VBox>
<InfoDisplay gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2" <InfoDisplay fx:id="amountPriceBoxInfo" gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"/>
text="%createOffer.amountPriceBox.info"/>
<Button fx:id="showPaymentInfoScreenButton" text="%createOffer.amountPriceBox.next" id="show-details-button" <Button fx:id="showPaymentInfoScreenButton" text="%createOffer.amountPriceBox.next" id="show-details-button"
GridPane.columnIndex="1" GridPane.rowIndex="3" defaultButton="true" GridPane.columnIndex="1" GridPane.rowIndex="3" defaultButton="true"

View file

@ -35,6 +35,7 @@ import io.bitsquare.gui.main.help.Help;
import io.bitsquare.gui.main.help.HelpId; import io.bitsquare.gui.main.help.HelpId;
import io.bitsquare.gui.main.portfolio.PortfolioView; import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.offer.OffersView; import io.bitsquare.gui.main.portfolio.offer.OffersView;
import io.bitsquare.gui.main.portfolio.pending.PendingTradesView;
import io.bitsquare.gui.main.trade.TradeView; import io.bitsquare.gui.main.trade.TradeView;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
@ -80,14 +81,14 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
@FXML AddressTextField addressTextField; @FXML AddressTextField addressTextField;
@FXML BalanceTextField balanceTextField; @FXML BalanceTextField balanceTextField;
@FXML ProgressIndicator placeOfferSpinner; @FXML ProgressIndicator placeOfferSpinner;
@FXML InfoDisplay advancedInfoDisplay, fundsBoxInfoDisplay; @FXML InfoDisplay amountPriceBoxInfo, advancedInfoDisplay, fundsBoxInfoDisplay;
@FXML TitledGroupBg priceAmountPane, payFundsPane, showDetailsPane; @FXML TitledGroupBg priceAmountPane, payFundsPane, showDetailsPane;
@FXML Button showPaymentInfoScreenButton, showAdvancedSettingsButton, placeOfferButton; @FXML Button showPaymentInfoScreenButton, showAdvancedSettingsButton, placeOfferButton;
@FXML InputTextField amountTextField, minAmountTextField, priceTextField, volumeTextField; @FXML InputTextField amountTextField, minAmountTextField, priceTextField, volumeTextField;
@FXML TextField acceptedArbitratorsTextField, totalToPayTextField, bankAccountTypeTextField, @FXML TextField acceptedArbitratorsTextField, totalToPayTextField, bankAccountTypeTextField,
bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField,
acceptedLanguagesTextField; acceptedLanguagesTextField;
@FXML Label buyLabel, addressLabel, balanceLabel, totalToPayLabel, totalToPayInfoIconLabel, bankAccountTypeLabel, @FXML Label buyLabel, amountToTradeLabel, addressLabel, balanceLabel, totalToPayLabel, totalToPayInfoIconLabel, bankAccountTypeLabel,
bankAccountCurrencyLabel, bankAccountCountyLabel, acceptedCountriesLabel, acceptedCountriesLabelIcon, bankAccountCurrencyLabel, bankAccountCountyLabel, acceptedCountriesLabel, acceptedCountriesLabelIcon,
acceptedLanguagesLabel, acceptedLanguagesLabelIcon, acceptedArbitratorsLabel, acceptedLanguagesLabel, acceptedLanguagesLabelIcon, acceptedArbitratorsLabel,
acceptedArbitratorsLabelIcon, amountBtcLabel, priceFiatLabel, volumeFiatLabel, minAmountBtcLabel, acceptedArbitratorsLabelIcon, amountBtcLabel, priceFiatLabel, volumeFiatLabel, minAmountBtcLabel,
@ -116,8 +117,8 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
protected void initialize() { protected void initialize() {
setupListeners(); setupListeners();
setupBindings(); setupBindings();
balanceTextField.setup(model.getWalletService(), model.address.get(),
model.getFormatter()); balanceTextField.setup(model.getWalletService(), model.address.get(), model.getFormatter());
volumeTextField.setPromptText(BSResources.get("createOffer.volume.prompt", model.fiatCode.get())); volumeTextField.setPromptText(BSResources.get("createOffer.volume.prompt", model.fiatCode.get()));
} }
@ -292,9 +293,9 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
model.showTransactionPublishedScreen.addListener((o, oldValue, newValue) -> { model.showTransactionPublishedScreen.addListener((o, oldValue, newValue) -> {
// TODO temp just for testing // TODO temp just for testing
// newValue = false; newValue = false;
// close(); close();
//navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class, OffersView.class); navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class, OffersView.class);
if (newValue) { if (newValue) {
overlayManager.blurContent(); overlayManager.blurContent();
@ -336,20 +337,17 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
minAmountBtcLabel.textProperty().bind(model.btcCode); minAmountBtcLabel.textProperty().bind(model.btcCode);
priceDescriptionLabel.textProperty().bind(createStringBinding(() -> priceDescriptionLabel.textProperty().bind(createStringBinding(() ->
BSResources.get("createOffer.amountPriceBox.priceDescription", BSResources.get("createOffer.amountPriceBox.priceDescription", model.fiatCode.get()), model.fiatCode));
model.fiatCode.get()),
model.fiatCode)); volumeDescriptionLabel.textProperty().bind(createStringBinding(() -> model.volumeDescriptionLabel.get(), model.fiatCode, model.volumeDescriptionLabel));
volumeDescriptionLabel.textProperty().bind(createStringBinding(() ->
BSResources.get("createOffer.amountPriceBox.volumeDescription",
model.fiatCode.get()),
model.fiatCode));
buyLabel.textProperty().bind(model.directionLabel); buyLabel.textProperty().bind(model.directionLabel);
amountToTradeLabel.textProperty().bind(model.amountToTradeLabel);
amountTextField.textProperty().bindBidirectional(model.amount); amountTextField.textProperty().bindBidirectional(model.amount);
minAmountTextField.textProperty().bindBidirectional(model.minAmount); minAmountTextField.textProperty().bindBidirectional(model.minAmount);
priceTextField.textProperty().bindBidirectional(model.price); priceTextField.textProperty().bindBidirectional(model.price);
volumeTextField.textProperty().bindBidirectional(model.volume); volumeTextField.textProperty().bindBidirectional(model.volume);
amountPriceBoxInfo.textProperty().bind(model.amountPriceBoxInfo);
totalToPayTextField.textProperty().bind(model.totalToPay); totalToPayTextField.textProperty().bind(model.totalToPay);
@ -471,19 +469,25 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
infoGridPane.setVgap(5); infoGridPane.setVgap(5);
infoGridPane.setPadding(new Insets(10, 10, 10, 10)); infoGridPane.setPadding(new Insets(10, 10, 10, 10));
addPayInfoEntry(infoGridPane, 0, int i = 0;
if (model.isSeller()) {
addPayInfoEntry(infoGridPane, i++,
BSResources.get("createOffer.fundsBox.tradeAmount"),
model.tradeAmount.get());
}
addPayInfoEntry(infoGridPane, i++,
BSResources.get("createOffer.fundsBox.securityDeposit"), BSResources.get("createOffer.fundsBox.securityDeposit"),
model.securityDeposit.get()); model.securityDeposit.get());
addPayInfoEntry(infoGridPane, 1, BSResources.get("createOffer.fundsBox.offerFee"), addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.offerFee"),
model.offerFee.get()); model.offerFee.get());
addPayInfoEntry(infoGridPane, 2, BSResources.get("createOffer.fundsBox.networkFee"), addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.networkFee"),
model.networkFee.get()); model.networkFee.get());
Separator separator = new Separator(); Separator separator = new Separator();
separator.setOrientation(Orientation.HORIZONTAL); separator.setOrientation(Orientation.HORIZONTAL);
separator.setStyle("-fx-background: #666;"); separator.setStyle("-fx-background: #666;");
GridPane.setConstraints(separator, 1, 3); GridPane.setConstraints(separator, 1, i++);
infoGridPane.getChildren().add(separator); infoGridPane.getChildren().add(separator);
addPayInfoEntry(infoGridPane, 4, BSResources.get("createOffer.fundsBox.total"), addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.total"),
model.totalToPay.get()); model.totalToPay.get());
totalToPayInfoPopover = new PopOver(infoGridPane); totalToPayInfoPopover = new PopOver(infoGridPane);
if (totalToPayInfoIconLabel.getScene() != null) { if (totalToPayInfoIconLabel.getScene() != null) {

View file

@ -50,13 +50,18 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
private final BSFormatter formatter; private final BSFormatter formatter;
private final FiatValidator fiatValidator; private final FiatValidator fiatValidator;
final StringProperty amount = new SimpleStringProperty(); final StringProperty amount = new SimpleStringProperty();
final StringProperty minAmount = new SimpleStringProperty(); final StringProperty minAmount = new SimpleStringProperty();
final StringProperty price = new SimpleStringProperty(); final StringProperty price = new SimpleStringProperty();
final StringProperty volume = new SimpleStringProperty(); final StringProperty volume = new SimpleStringProperty();
final StringProperty volumeDescriptionLabel = new SimpleStringProperty();
final StringProperty amountPriceBoxInfo = new SimpleStringProperty();
final StringProperty securityDeposit = new SimpleStringProperty(); final StringProperty securityDeposit = new SimpleStringProperty();
final StringProperty tradeAmount = new SimpleStringProperty();
final StringProperty totalToPay = new SimpleStringProperty(); final StringProperty totalToPay = new SimpleStringProperty();
final StringProperty directionLabel = new SimpleStringProperty(); final StringProperty directionLabel = new SimpleStringProperty();
final StringProperty amountToTradeLabel = new SimpleStringProperty();
final StringProperty offerFee = new SimpleStringProperty(); final StringProperty offerFee = new SimpleStringProperty();
final StringProperty networkFee = new SimpleStringProperty(); final StringProperty networkFee = new SimpleStringProperty();
final StringProperty bankAccountType = new SimpleStringProperty(); final StringProperty bankAccountType = new SimpleStringProperty();
@ -113,9 +118,21 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
// setOfferBookFilter is a one time call // setOfferBookFilter is a one time call
void initWithData(Offer.Direction direction, Coin amount, Fiat price) { void initWithData(Offer.Direction direction, Coin amount, Fiat price) {
dataModel.setDirection(direction); dataModel.initWithData( direction, amount, price);
directionLabel.set(dataModel.getDirection() == Offer.Direction.BUY ? BSResources.get("shared.buy") : BSResources.get
("shared.sell")); if (dataModel.getDirection() == Offer.Direction.BUY) {
directionLabel.set(BSResources.get("shared.buyBitcoin"));
amountToTradeLabel.set(BSResources.get("createOffer.amountPriceBox.amountDescription", BSResources.get("shared.buy")));
volumeDescriptionLabel.set(BSResources.get("createOffer.amountPriceBox.buy.volumeDescription", fiatCode.get()));
amountPriceBoxInfo.set(BSResources.get("createOffer.amountPriceBox.buy.info"));
}
else {
directionLabel.set(BSResources.get("shared.sellBitcoin"));
amountToTradeLabel.set(BSResources.get("createOffer.amountPriceBox.amountDescription", BSResources.get("shared.sell")));
volumeDescriptionLabel.set(BSResources.get("createOffer.amountPriceBox.sell.volumeDescription", fiatCode.get()));
amountPriceBoxInfo.set(BSResources.get("createOffer.amountPriceBox.sell.info"));
}
// apply only if valid // apply only if valid
boolean amountValid = false; boolean amountValid = false;
@ -327,6 +344,9 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
securityDeposit.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.securityDepositAsCoin.get()), securityDeposit.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.securityDepositAsCoin.get()),
dataModel.securityDepositAsCoin)); dataModel.securityDepositAsCoin));
tradeAmount.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.amountAsCoin.get()),
dataModel.amountAsCoin));
totalToPayAsCoin.bind(dataModel.totalToPayAsCoin); totalToPayAsCoin.bind(dataModel.totalToPayAsCoin);
offerFee.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.offerFeeAsCoin.get()), offerFee.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.offerFeeAsCoin.get()),
@ -407,4 +427,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
return fiatValidator.validate(input); return fiatValidator.validate(input);
} }
boolean isSeller() {
return dataModel.getDirection() == Offer.Direction.SELL;
}
} }

View file

@ -145,9 +145,9 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
table.sort(); table.sort();
//TODO temp for testing //TODO temp for testing
/* amountTextField.setText("1"); amountTextField.setText("1");
priceTextField.setText("300"); priceTextField.setText("300");
volumeTextField.setText("300");*/ volumeTextField.setText("300");
} }
@Override @Override
@ -227,8 +227,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer); offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer);
} }
else { else {
Popups.openInfoPopup("Not implemented yet", offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer);
"At the moment you can only take offers in the Sell BTC screen.");
} }
} }
else { else {

View file

@ -98,6 +98,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
void initWithData(Coin amount, Offer offer) { void initWithData(Coin amount, Offer offer) {
this.offer = offer; this.offer = offer;
securityDepositAsCoin.set(offer.getSecurityDeposit());
if (amount != null && if (amount != null &&
!amount.isGreaterThan(offer.getAmount()) && !amount.isGreaterThan(offer.getAmount()) &&
@ -108,7 +109,6 @@ class TakeOfferDataModel implements Activatable, DataModel {
amountAsCoin.set(offer.getAmount()); amountAsCoin.set(offer.getAmount());
} }
securityDepositAsCoin.set(offer.getSecurityDeposit());
calculateVolume(); calculateVolume();
calculateTotalToPay(); calculateTotalToPay();
@ -143,17 +143,15 @@ class TakeOfferDataModel implements Activatable, DataModel {
} }
void calculateTotalToPay() { void calculateTotalToPay() {
try { if (getDirection() == Offer.Direction.SELL)
if (securityDepositAsCoin.get() != null) { totalToPayAsCoin.set(offerFeeAsCoin.get().add(networkFeeAsCoin.get()).add(securityDepositAsCoin.get()));
totalToPayAsCoin.set(offerFeeAsCoin.get().add(amountAsCoin.get()).add(networkFeeAsCoin.get()).add else
(securityDepositAsCoin.get())); totalToPayAsCoin.set(offerFeeAsCoin.get().add(networkFeeAsCoin.get()).add(securityDepositAsCoin.get()).add(amountAsCoin.get()));
}
} catch (Throwable t) {
// Should be never reached
log.error(t.toString());
}
} }
Offer.Direction getDirection() {
return offer.getDirection();
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted") @SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isMinAmountLessOrEqualAmount() { boolean isMinAmountLessOrEqualAmount() {

View file

@ -67,8 +67,7 @@
<Insets right="10.0" top="20.0"/> <Insets right="10.0" top="20.0"/>
</GridPane.margin> </GridPane.margin>
<VBox spacing="4"> <VBox spacing="4">
<Label id="input-description-label" text="%takeOffer.amountPriceBox.amountDescription" <Label fx:id="amountDescriptionLabel" id="input-description-label" prefWidth="170"/>
prefWidth="170"/>
<HBox> <HBox>
<InputTextField fx:id="amountTextField" id="text-input-with-currency-text-field" <InputTextField fx:id="amountTextField" id="text-input-with-currency-text-field"
promptText="%takeOffer.amount.prompt" prefWidth="170" promptText="%takeOffer.amount.prompt" prefWidth="170"
@ -120,8 +119,7 @@
style=" -fx-alignment: center;"/> style=" -fx-alignment: center;"/>
</VBox> </VBox>
<InfoDisplay gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2" <InfoDisplay fx:id="amountPriceBoxInfoDisplay" gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"/>
text="%takeOffer.amountPriceBox.info"/>
<Label fx:id="isOfferAvailableLabel" text="%takeOffer.fundsBox.isOfferAvailable" GridPane.rowIndex="3"> <Label fx:id="isOfferAvailableLabel" text="%takeOffer.fundsBox.isOfferAvailable" GridPane.rowIndex="3">
<GridPane.margin> <GridPane.margin>
@ -179,8 +177,7 @@
</GridPane.margin> </GridPane.margin>
</BalanceTextField> </BalanceTextField>
<InfoDisplay fx:id="fundsBoxInfoDisplay" gridPane="$gridPane" onAction="#onOpenFundingHelp" rowIndex="7" <InfoDisplay fx:id="fundsBoxInfoDisplay" gridPane="$gridPane" onAction="#onOpenFundingHelp" rowIndex="7" visible="false"/>
text="%takeOffer.fundsBox.info" visible="false"/>
<HBox spacing="10" GridPane.columnIndex="1" GridPane.rowIndex="8"> <HBox spacing="10" GridPane.columnIndex="1" GridPane.rowIndex="8">
<Button fx:id="showAdvancedSettingsButton" text="%takeOffer.fundsBox.showAdvanced" <Button fx:id="showAdvancedSettingsButton" text="%takeOffer.fundsBox.showAdvanced"

View file

@ -67,6 +67,8 @@ import org.controlsfx.control.action.AbstractAction;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.controlsfx.dialog.Dialog; import org.controlsfx.dialog.Dialog;
import static javafx.beans.binding.Bindings.createStringBinding;
@FxmlView @FxmlView
public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOfferViewModel> { public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOfferViewModel> {
@ -76,13 +78,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
@FXML AddressTextField addressTextField; @FXML AddressTextField addressTextField;
@FXML BalanceTextField balanceTextField; @FXML BalanceTextField balanceTextField;
@FXML ProgressIndicator takeOfferSpinner, isOfferAvailableProgressIndicator; @FXML ProgressIndicator takeOfferSpinner, isOfferAvailableProgressIndicator;
@FXML InfoDisplay advancedInfoDisplay, fundsBoxInfoDisplay; @FXML InfoDisplay amountPriceBoxInfoDisplay, advancedInfoDisplay, fundsBoxInfoDisplay;
@FXML TitledGroupBg priceAmountPane, payFundsPane, showDetailsPane; @FXML TitledGroupBg priceAmountPane, payFundsPane, showDetailsPane;
@FXML Button showPaymentInfoScreenButton, showAdvancedSettingsButton, takeOfferButton; @FXML Button showPaymentInfoScreenButton, showAdvancedSettingsButton, takeOfferButton;
@FXML TextField priceTextField, volumeTextField, acceptedArbitratorsTextField, totalToPayTextField, @FXML TextField priceTextField, volumeTextField, acceptedArbitratorsTextField, totalToPayTextField,
bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField,
acceptedCountriesTextField, acceptedLanguagesTextField; acceptedCountriesTextField, acceptedLanguagesTextField;
@FXML Label isOfferAvailableLabel, buyLabel, addressLabel, amountRangeTextField, balanceLabel, totalToPayLabel, @FXML Label isOfferAvailableLabel, buyLabel, addressLabel, amountDescriptionLabel, amountRangeTextField, balanceLabel, totalToPayLabel,
totalToPayInfoIconLabel, totalToPayInfoIconLabel,
bankAccountTypeLabel, bankAccountCurrencyLabel, bankAccountCountyLabel, acceptedCountriesLabel, bankAccountTypeLabel, bankAccountCurrencyLabel, bankAccountCountyLabel, acceptedCountriesLabel,
acceptedLanguagesLabel, acceptedArbitratorsLabel, amountBtcLabel, priceDescriptionLabel, acceptedLanguagesLabel, acceptedArbitratorsLabel, amountBtcLabel, priceDescriptionLabel,
@ -118,16 +120,17 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
model.errorMessage.removeListener(errorMessageChangeListener); model.errorMessage.removeListener(errorMessageChangeListener);
} }
public void initWithData(Offer.Direction direction, Coin amount, Offer offer) { public void initWithData(Coin amount, Offer offer) {
model.initWithData(direction, amount, offer); model.initWithData(amount, offer);
if (direction == Offer.Direction.BUY) if (offer.getDirection() == Offer.Direction.SELL)
imageView.setId("image-buy-large"); imageView.setId("image-buy-large");
else else
imageView.setId("image-sell-large"); imageView.setId("image-sell-large");
priceDescriptionLabel.setText(BSResources.get("takeOffer.amountPriceBox.priceDescription", model.getFiatCode())); priceDescriptionLabel.setText(BSResources.get("takeOffer.amountPriceBox.priceDescription", model.getFiatCode()));
volumeDescriptionLabel.setText(BSResources.get("takeOffer.amountPriceBox.volumeDescription", model.getFiatCode())); volumeDescriptionLabel.setText(BSResources.get("takeOffer.amountPriceBox.volumeDescription", model.getFiatCode()));
volumeDescriptionLabel.textProperty().bind(createStringBinding(() -> model.volumeDescriptionLabel.get(), model.fiatCode, model.volumeDescriptionLabel));
balanceTextField.setup(model.getWalletService(), model.address.get(), model.getFormatter()); balanceTextField.setup(model.getWalletService(), model.address.get(), model.getFormatter());
@ -144,6 +147,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
acceptedLanguagesTextField.setText(model.getAcceptedLanguages()); acceptedLanguagesTextField.setText(model.getAcceptedLanguages());
acceptedArbitratorsTextField.setText(model.getAcceptedArbitratorIds()); acceptedArbitratorsTextField.setText(model.getAcceptedArbitratorIds());
amountPriceBoxInfoDisplay.textProperty().bind(model.amountPriceBoxInfo);
fundsBoxInfoDisplay.textProperty().bind(model.fundsBoxInfoDisplay);
showCheckAvailabilityScreen(); showCheckAvailabilityScreen();
} }
@ -243,9 +248,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
model.showTransactionPublishedScreen.addListener((o, oldValue, newValue) -> { model.showTransactionPublishedScreen.addListener((o, oldValue, newValue) -> {
// TODO temp just for testing // TODO temp just for testing
/* newValue = false; newValue = false;
close();*/ close();
//navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class); navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
if (newValue) { if (newValue) {
overlayManager.blurContent(); overlayManager.blurContent();
@ -287,6 +292,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
volumeTextField.textProperty().bindBidirectional(model.volume); volumeTextField.textProperty().bindBidirectional(model.volume);
totalToPayTextField.textProperty().bind(model.totalToPay); totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.totalToPayAsCoin); addressTextField.amountAsCoinProperty().bind(model.totalToPayAsCoin);
amountDescriptionLabel.textProperty().bind(model.amountDescription);
// Validation // Validation
amountTextField.validationResultProperty().bind(model.amountValidationResult); amountTextField.validationResultProperty().bind(model.amountValidationResult);
@ -429,22 +436,27 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
infoGridPane.setVgap(5); infoGridPane.setVgap(5);
infoGridPane.setPadding(new Insets(10, 10, 10, 10)); infoGridPane.setPadding(new Insets(10, 10, 10, 10));
addPayInfoEntry(infoGridPane, 0, int i = 0;
if (model.isSeller()) {
addPayInfoEntry(infoGridPane, i++,
BSResources.get("takeOffer.fundsBox.amount"), BSResources.get("takeOffer.fundsBox.amount"),
model.getAmount()); model.getAmount());
addPayInfoEntry(infoGridPane, 1, }
addPayInfoEntry(infoGridPane, i++,
BSResources.get("takeOffer.fundsBox.securityDeposit"), BSResources.get("takeOffer.fundsBox.securityDeposit"),
model.securityDeposit.get()); model.securityDeposit.get());
addPayInfoEntry(infoGridPane, 2, BSResources.get("takeOffer.fundsBox.offerFee"), addPayInfoEntry(infoGridPane, i++, BSResources.get("takeOffer.fundsBox.offerFee"),
model.getOfferFee()); model.getOfferFee());
addPayInfoEntry(infoGridPane, 3, BSResources.get("takeOffer.fundsBox.networkFee"), addPayInfoEntry(infoGridPane, i++, BSResources.get("takeOffer.fundsBox.networkFee"),
model.getNetworkFee()); model.getNetworkFee());
Separator separator = new Separator(); Separator separator = new Separator();
separator.setOrientation(Orientation.HORIZONTAL); separator.setOrientation(Orientation.HORIZONTAL);
separator.setStyle("-fx-background: #666;"); separator.setStyle("-fx-background: #666;");
GridPane.setConstraints(separator, 1, 4); GridPane.setConstraints(separator, 1, i++);
infoGridPane.getChildren().add(separator); infoGridPane.getChildren().add(separator);
addPayInfoEntry(infoGridPane, 5, BSResources.get("takeOffer.fundsBox.total"), addPayInfoEntry(infoGridPane, i++, BSResources.get("takeOffer.fundsBox.total"),
model.totalToPay.get()); model.totalToPay.get());
totalToPayInfoPopover = new PopOver(infoGridPane); totalToPayInfoPopover = new PopOver(infoGridPane);
if (totalToPayInfoIconLabel.getScene() != null) { if (totalToPayInfoIconLabel.getScene() != null) {

View file

@ -26,6 +26,8 @@ import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import org.bitcoinj.core.Address; import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -54,7 +56,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
DETAILS_SCREEN DETAILS_SCREEN
} }
private String fiatCode;
private String amountRange; private String amountRange;
private String price; private String price;
private String directionLabel; private String directionLabel;
@ -85,7 +86,11 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
final StringProperty transactionId = new SimpleStringProperty(); final StringProperty transactionId = new SimpleStringProperty();
final StringProperty errorMessage = new SimpleStringProperty(); final StringProperty errorMessage = new SimpleStringProperty();
final StringProperty btcCode = new SimpleStringProperty(); final StringProperty btcCode = new SimpleStringProperty();
final StringProperty amountDescription = new SimpleStringProperty();
final StringProperty volumeDescriptionLabel = new SimpleStringProperty();
final StringProperty fiatCode = new SimpleStringProperty();
final StringProperty amountPriceBoxInfo = new SimpleStringProperty();
final StringProperty fundsBoxInfoDisplay = new SimpleStringProperty();
final BooleanProperty takeOfferButtonDisabled = new SimpleBooleanProperty(false); final BooleanProperty takeOfferButtonDisabled = new SimpleBooleanProperty(false);
final BooleanProperty isTakeOfferSpinnerVisible = new SimpleBooleanProperty(false); final BooleanProperty isTakeOfferSpinnerVisible = new SimpleBooleanProperty(false);
@ -115,18 +120,31 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
} }
// setOfferBookFilter is a one time call // setOfferBookFilter is a one time call
void initWithData(Offer.Direction direction, Coin amount, Offer offer) { void initWithData(Coin amount, Offer offer) {
dataModel.initWithData(amount, offer); dataModel.initWithData(amount, offer);
directionLabel = direction == Offer.Direction.BUY ? directionLabel = offer.getDirection() == Offer.Direction.SELL ?
BSResources.get("shared.buy") : BSResources.get("shared.sell"); BSResources.get("shared.buyBitcoin") : BSResources.get("shared.sellBitcoin");
fiatCode = offer.getCurrencyCode(); fiatCode.set(offer.getCurrencyCode());
if (!dataModel.isMinAmountLessOrEqualAmount()) { if (!dataModel.isMinAmountLessOrEqualAmount()) {
amountValidationResult.set(new InputValidator.ValidationResult(false, amountValidationResult.set(new InputValidator.ValidationResult(false,
BSResources.get("takeOffer.validation.amountSmallerThanMinAmount"))); BSResources.get("takeOffer.validation.amountSmallerThanMinAmount")));
} }
if (dataModel.getDirection() == Offer.Direction.BUY) {
amountDescription.set(BSResources.get("takeOffer.amountPriceBox.buy.amountDescription", offer.getId()));
volumeDescriptionLabel.set(BSResources.get("takeOffer.amountPriceBox.buy.volumeDescription", fiatCode.get()));
amountPriceBoxInfo.set(BSResources.get("takeOffer.amountPriceBox.buy.info"));
fundsBoxInfoDisplay.set(BSResources.get("takeOffer.fundsBox.buy.info"));
}
else {
amountDescription.set(BSResources.get("takeOffer.amountPriceBox.sell.amountDescription", offer.getId()));
volumeDescriptionLabel.set(BSResources.get("takeOffer.amountPriceBox.sell.volumeDescription", fiatCode.get()));
amountPriceBoxInfo.set(BSResources.get("takeOffer.amountPriceBox.sell.info"));
fundsBoxInfoDisplay.set(BSResources.get("takeOffer.fundsBox.sell.info"));
}
//model.volumeAsFiat.set(offer.getVolumeByAmount(model.amountAsCoin.get())); //model.volumeAsFiat.set(offer.getVolumeByAmount(model.amountAsCoin.get()));
amountRange = formatter.formatCoinWithCode(offer.getMinAmount()) + " - " + amountRange = formatter.formatCoinWithCode(offer.getMinAmount()) + " - " +
@ -210,11 +228,13 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
dataModel.takeOffer((takerTrade) -> { dataModel.takeOffer((takerTrade) -> {
takerTrade.processStateProperty().addListener((ov, oldValue, newValue) -> { takerTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("takerTrade state = " + newValue); log.debug("takerTrade state = " + newValue);
String msg = ""; String msg = "";
if (takerTrade.getErrorMessage() != null) if (takerTrade.getErrorMessage() != null)
msg = "\nError message: " + takerTrade.getErrorMessage(); msg = "\nError message: " + takerTrade.getErrorMessage();
switch (newValue) { if (takerTrade instanceof TakerAsBuyerTrade) {
switch ((TakerAsBuyerTrade.ProcessState) newValue) {
case TAKE_OFFER_FEE_TX_CREATED: case TAKE_OFFER_FEE_TX_CREATED:
break; break;
case DEPOSIT_PUBLISHED: case DEPOSIT_PUBLISHED:
@ -244,6 +264,39 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
log.warn("Unhandled takerTrade state: " + newValue); log.warn("Unhandled takerTrade state: " + newValue);
break; break;
} }
}
else if (takerTrade instanceof TakerAsSellerTrade) {
switch ((TakerAsSellerTrade.ProcessState) newValue) {
case TAKE_OFFER_FEE_TX_CREATED:
break;
case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED:
assert takerTrade.getDepositTx() != null;
transactionId.set(takerTrade.getDepositTx().getHashAsString());
applyTakeOfferRequestResult(true);
break;
case FIAT_PAYMENT_STARTED:
break;
case TAKE_OFFER_FEE_PUBLISH_FAILED:
errorMessage.set("An error occurred when paying the takerTrade fee." + msg);
takeOfferRequested = false;
break;
case MESSAGE_SENDING_FAILED:
errorMessage.set("An error occurred when sending a message to the offerer. Maybe there are connection problems. " +
"Please try later again." + msg);
takeOfferRequested = false;
break;
case PAYOUT_PUBLISHED:
break;
case EXCEPTION:
errorMessage.set(msg);
takeOfferRequested = false;
break;
default:
log.warn("Unhandled takerTrade state: " + newValue);
break;
}
}
if (errorMessage.get() != null) { if (errorMessage.get() != null) {
isAmountAndPriceValidAndWalletFunded = false; isAmountAndPriceValidAndWalletFunded = false;
@ -255,6 +308,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
}); });
} }
boolean isSeller() {
return dataModel.getDirection() == Offer.Direction.BUY;
}
void securityDepositInfoDisplayed() { void securityDepositInfoDisplayed() {
dataModel.securityDepositInfoDisplayed(); dataModel.securityDepositInfoDisplayed();
} }
@ -307,7 +364,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
} }
String getFiatCode() { String getFiatCode() {
return fiatCode; return fiatCode.get();
} }
String getAmount() { String getAmount() {

View file

@ -24,6 +24,6 @@ public class Colors {
public static final Paint LIGHT_GREY = Color.valueOf("#CCCCCC"); public static final Paint LIGHT_GREY = Color.valueOf("#CCCCCC");
public static final Paint MID_GREY = Color.valueOf("#666666"); public static final Paint MID_GREY = Color.valueOf("#666666");
public static final Paint DARK_GREY = Color.valueOf("#333333"); public static final Paint DARK_GREY = Color.valueOf("#333333");
public static final Paint GREEN = Color.valueOf("#00AA00"); public static final Paint GREEN = Color.valueOf("#00aa33");
} }

View file

@ -0,0 +1,227 @@
/*
* 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.gui.util;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.components.TextFieldWithCopyIcon;
import io.bitsquare.gui.components.TitledGroupBg;
import io.bitsquare.gui.components.TxIdTextField;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ComponentBuilder {
private static final Logger log = LoggerFactory.getLogger(ComponentBuilder.class);
public static GridPane getAndAddGridPane(Pane parent) {
GridPane gridPane = new GridPane();
AnchorPane.setLeftAnchor(gridPane, 10d);
AnchorPane.setRightAnchor(gridPane, 10d);
AnchorPane.setTopAnchor(gridPane, 10d);
AnchorPane.setBottomAnchor(gridPane, 10d);
gridPane.setHgap(Layout.GRID_GAP);
gridPane.setVgap(Layout.GRID_GAP);
ColumnConstraints columnConstraints1 = new ColumnConstraints();
columnConstraints1.setHalignment(HPos.RIGHT);
columnConstraints1.setHgrow(Priority.SOMETIMES);
ColumnConstraints columnConstraints2 = new ColumnConstraints();
columnConstraints2.setHgrow(Priority.ALWAYS);
gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
parent.getChildren().add(gridPane);
return gridPane;
}
public static TitledGroupBg getAndAddTitledGroupBg(GridPane gridPane, int rowIndex, int rowSpan, String title) {
return getAndAddTitledGroupBg(gridPane, rowIndex, rowSpan, title, 0);
}
public static TitledGroupBg getAndAddTitledGroupBg(GridPane gridPane, int rowIndex, int rowSpan, String title, double top) {
TitledGroupBg titledGroupBg = new TitledGroupBg();
titledGroupBg.setText(title);
titledGroupBg.prefWidthProperty().bind(gridPane.widthProperty());
GridPane.setRowIndex(titledGroupBg, rowIndex);
GridPane.setRowSpan(titledGroupBg, rowSpan);
GridPane.setColumnSpan(titledGroupBg, 2);
GridPane.setMargin(titledGroupBg, new Insets(top, -10, -10, -10));
gridPane.getChildren().add(titledGroupBg);
return titledGroupBg;
}
private static Label getAndAddLabel(GridPane gridPane, int rowIndex, String title, double top) {
Label label = new Label(title);
GridPane.setRowIndex(label, rowIndex);
GridPane.setMargin(label, new Insets(top, 0, 0, 0));
gridPane.getChildren().add(label);
return label;
}
public static LabelTextFieldPair getAndAddLabelTextFieldPair(GridPane gridPane, int rowIndex, String title) {
return getAndAddLabelTextFieldPair(gridPane, rowIndex, title, 0);
}
public static LabelTextFieldPair getAndAddLabelTextFieldPair(GridPane gridPane, int rowIndex, String title, double top) {
Label label = getAndAddLabel(gridPane, rowIndex, title, top);
TextField textField = new TextField();
textField.setEditable(false);
textField.setMouseTransparent(true);
textField.setFocusTraversable(false);
GridPane.setRowIndex(textField, rowIndex);
GridPane.setColumnIndex(textField, 1);
GridPane.setMargin(textField, new Insets(top, 0, 0, 0));
gridPane.getChildren().add(textField);
return new LabelTextFieldPair(label, textField);
}
public static LabelInputTextFieldPair getAndAddLabelInputTextFieldPair(GridPane gridPane, int rowIndex, String title) {
return getAndAddLabelInputTextFieldPair(gridPane, rowIndex, title, 0);
}
public static LabelInputTextFieldPair getAndAddLabelInputTextFieldPair(GridPane gridPane, int rowIndex, String title, double top) {
Label label = getAndAddLabel(gridPane, rowIndex, title, top);
InputTextField inputTextField = new InputTextField();
GridPane.setRowIndex(inputTextField, rowIndex);
GridPane.setColumnIndex(inputTextField, 1);
GridPane.setMargin(inputTextField, new Insets(top, 0, 0, 0));
gridPane.getChildren().add(inputTextField);
return new LabelInputTextFieldPair(label, inputTextField);
}
public static LabelTxIdTextFieldPair getAndAddLabelTxIdTextFieldPair(GridPane gridPane, int rowIndex, String title) {
return getAndAddLabelTxIdTextFieldPair(gridPane, rowIndex, title, 0);
}
public static LabelTxIdTextFieldPair getAndAddLabelTxIdTextFieldPair(GridPane gridPane, int rowIndex, String title, double top) {
Label label = getAndAddLabel(gridPane, rowIndex, title, top);
TxIdTextField txIdTextField = new TxIdTextField();
GridPane.setRowIndex(txIdTextField, rowIndex);
GridPane.setColumnIndex(txIdTextField, 1);
GridPane.setMargin(txIdTextField, new Insets(top, 0, 0, 0));
gridPane.getChildren().add(txIdTextField);
return new LabelTxIdTextFieldPair(label, txIdTextField);
}
public static LabelTextFieldWithCopyIconPair getAndAddLabelTextFieldWithCopyIconPair(GridPane gridPane, int rowIndex, String title) {
return getAndAddLabelTextFieldWithCopyIconPair(gridPane, rowIndex, title, 0);
}
public static LabelTextFieldWithCopyIconPair getAndAddLabelTextFieldWithCopyIconPair(GridPane gridPane, int rowIndex, String title, double top) {
Label label = getAndAddLabel(gridPane, rowIndex, title, top);
TextFieldWithCopyIcon textFieldWithCopyIcon = new TextFieldWithCopyIcon();
GridPane.setRowIndex(textFieldWithCopyIcon, rowIndex);
GridPane.setColumnIndex(textFieldWithCopyIcon, 1);
GridPane.setMargin(textFieldWithCopyIcon, new Insets(top, 0, 0, 0));
gridPane.getChildren().add(textFieldWithCopyIcon);
return new LabelTextFieldWithCopyIconPair(label, textFieldWithCopyIcon);
}
public static InfoDisplay getAndAddInfoDisplay(GridPane gridPane,
int rowIndex,
String text,
EventHandler<ActionEvent> onActionHandler) {
return getAndAddInfoDisplay(gridPane, rowIndex, text, onActionHandler, 0);
}
public static InfoDisplay getAndAddInfoDisplay(GridPane gridPane,
int rowIndex,
String text,
EventHandler<ActionEvent> onActionHandler,
double top) {
InfoDisplay infoDisplay = new InfoDisplay();
infoDisplay.setText(text);
infoDisplay.setOnAction(onActionHandler);
GridPane.setRowIndex(infoDisplay, rowIndex);
GridPane.setMargin(infoDisplay, new Insets(top, 0, 0, 0));
gridPane.getChildren().add(infoDisplay);
return infoDisplay;
}
public static Button getAndAddButton(GridPane gridPane,
int rowIndex,
String title,
EventHandler<ActionEvent> onActionHandler) {
Button button = new Button(title);
button.setDefaultButton(true);
button.setOnAction(onActionHandler);
GridPane.setRowIndex(button, rowIndex);
GridPane.setColumnIndex(button, 1);
GridPane.setMargin(button, new Insets(15, 0, 40, 0));
gridPane.getChildren().add(button);
return button;
}
public static class LabelTextFieldPair {
public Label label;
public TextField textField;
public LabelTextFieldPair(Label label, TextField textField) {
this.label = label;
this.textField = textField;
}
}
public static class LabelInputTextFieldPair {
public Label label;
public InputTextField inputTextField;
public LabelInputTextFieldPair(Label label, InputTextField inputTextField) {
this.label = label;
this.inputTextField = inputTextField;
}
}
public static class LabelTxIdTextFieldPair {
public Label label;
public TxIdTextField txIdTextField;
public LabelTxIdTextFieldPair(Label label, TxIdTextField txIdTextField) {
this.label = label;
this.txIdTextField = txIdTextField;
}
}
public static class LabelTextFieldWithCopyIconPair {
public Label label;
public TextFieldWithCopyIcon textFieldWithCopyIcon;
public LabelTextFieldWithCopyIconPair(Label label, TextFieldWithCopyIcon textFieldWithCopyIcon) {
this.label = label;
this.textFieldWithCopyIcon = textFieldWithCopyIcon;
}
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.gui.util;
public class Layout {
public static final double FIRST_ROW_DISTANCE = 20d;
public static final double GROUP_DISTANCE = 40d;
public static final double FIRST_ROW_AND_GROUP_DISTANCE = GROUP_DISTANCE+FIRST_ROW_DISTANCE;
public static double PADDING_WINDOW = 20d;
public static double PADDING = 10d;
public static double SPACING_HBOX = 10d;
public static double SPACING_VBOX = 5d;
public static double GRID_GAP = 5d;
}

View file

@ -0,0 +1,151 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade;
import io.bitsquare.offer.Offer;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.offerer.OffererAsBuyerProtocol;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererAsBuyerTrade extends OffererTrade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(OffererAsBuyerTrade.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public enum LifeCycleState implements OffererTrade.LifeCycleState {
OFFER_OPEN,
OFFER_RESERVED,
OFFER_CANCELED,
PENDING,
COMPLETED,
FAILED
}
public enum ProcessState implements OffererTrade.ProcessState {
UNDEFINED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
EXCEPTION
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public OffererAsBuyerTrade(Offer offer, Storage<? extends TradeList> storage) {
super(offer, storage);
log.trace("Created by constructor");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties();
initAmountProperty();
}
@Override
protected void createProtocol() {
protocol = new OffererAsBuyerProtocol(this);
}
@Override
protected void initStates() {
processState = ProcessState.UNDEFINED;
lifeCycleState = LifeCycleState.OFFER_OPEN;
initStateProperties();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Fiat
///////////////////////////////////////////////////////////////////////////////////////////
public void onFiatPaymentStarted() {
assert protocol instanceof OffererAsBuyerProtocol;
((OffererAsBuyerProtocol) protocol).onFiatPaymentStarted();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void setProcessState(Trade.ProcessState processState) {
super.setProcessState(processState);
switch ((ProcessState) processState) {
case EXCEPTION:
disposeProtocol();
setLifeCycleState(LifeCycleState.FAILED);
break;
}
}
@Override
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
super.setLifeCycleState(lifeCycleState);
switch ((LifeCycleState) lifeCycleState) {
case FAILED:
disposeProtocol();
break;
case COMPLETED:
disposeProtocol();
break;
}
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(ProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void handleConfidenceResult() {
if (((ProcessState) processState).ordinal() < ProcessState.DEPOSIT_CONFIRMED.ordinal())
setProcessState(ProcessState.DEPOSIT_CONFIRMED);
}
}

View file

@ -0,0 +1,153 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade;
import io.bitsquare.offer.Offer;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.offerer.OffererAsSellerProtocol;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererAsSellerTrade extends OffererTrade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(OffererAsSellerTrade.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public enum LifeCycleState implements OffererTrade.LifeCycleState {
OFFER_OPEN,
OFFER_RESERVED,
OFFER_CANCELED,
PENDING,
COMPLETED,
FAILED
}
public enum ProcessState implements OffererTrade.ProcessState {
UNDEFINED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
FIAT_PAYMENT_RECEIVED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
EXCEPTION
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public OffererAsSellerTrade(Offer offer, Storage<? extends TradeList> storage) {
super(offer, storage);
log.trace("Created by constructor");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties();
initAmountProperty();
}
@Override
protected void createProtocol() {
protocol = new OffererAsSellerProtocol(this);
}
@Override
protected void initStates() {
processState = ProcessState.UNDEFINED;
lifeCycleState = LifeCycleState.OFFER_OPEN;
initStateProperties();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Fiat
///////////////////////////////////////////////////////////////////////////////////////////
public void onFiatPaymentReceived() {
assert protocol instanceof OffererAsSellerProtocol;
((OffererAsSellerProtocol) protocol).onFiatPaymentReceived();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void setProcessState(Trade.ProcessState processState) {
super.setProcessState(processState);
switch ((ProcessState) processState) {
case EXCEPTION:
disposeProtocol();
setLifeCycleState(LifeCycleState.FAILED);
break;
}
}
@Override
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
super.setLifeCycleState(lifeCycleState);
switch ((LifeCycleState) lifeCycleState) {
case FAILED:
disposeProtocol();
break;
case COMPLETED:
disposeProtocol();
break;
}
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(ProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void handleConfidenceResult() {
if (((ProcessState) processState).ordinal() < ProcessState.DEPOSIT_CONFIRMED.ordinal())
setProcessState(ProcessState.DEPOSIT_CONFIRMED);
}
}

View file

@ -21,18 +21,11 @@ import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.ProcessModel; import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.trade.protocol.trade.offerer.OffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel; import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
@ -43,12 +36,10 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class OffererTrade extends Trade implements Serializable { public abstract class OffererTrade extends Trade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -59,26 +50,10 @@ public class OffererTrade extends Trade implements Serializable {
// Enum // Enum
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public enum OffererLifeCycleState implements LifeCycleState { public interface LifeCycleState extends Trade.LifeCycleState {
OFFER_OPEN,
OFFER_RESERVED,
OFFER_CANCELED,
PENDING,
COMPLETED,
FAILED
} }
public enum OffererProcessState implements ProcessState { public interface ProcessState extends Trade.ProcessState {
UNDEFINED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
EXCEPTION
} }
@ -86,31 +61,23 @@ public class OffererTrade extends Trade implements Serializable {
// Fields // Fields
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Transient/Immutable
transient private ObjectProperty<OffererProcessState> processStateProperty;
transient private ObjectProperty<OffererLifeCycleState> lifeCycleStateProperty;
// Mutable // Mutable
private Coin tradeAmount; protected Coin tradeAmount;
private Peer tradingPeer; protected Peer tradingPeer;
private OffererProcessState processState; transient protected ObjectProperty<Coin> tradeAmountProperty;
private OffererLifeCycleState lifeCycleState; transient protected ObjectProperty<Fiat> tradeVolumeProperty;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public OffererTrade(Offer offer, Storage<? extends TradeList> storage) { protected OffererTrade(Offer offer, Storage<? extends TradeList> storage) {
super(offer, storage); super(offer, storage);
log.trace("Created by constructor"); log.trace("Created by constructor");
processState = OffererProcessState.UNDEFINED; initStates();
lifeCycleState = OffererLifeCycleState.OFFER_OPEN; initStateProperties();
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(); tradeAmountProperty = new SimpleObjectProperty<>();
tradeVolumeProperty = new SimpleObjectProperty<>(); tradeVolumeProperty = new SimpleObjectProperty<>();
} }
@ -119,87 +86,24 @@ public class OffererTrade extends Trade implements Serializable {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form."); log.trace("Created from serialized form.");
processStateProperty = new SimpleObjectProperty<>(processState); initStateProperties();
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState); initAmountProperty();
tradeAmountProperty = new SimpleObjectProperty<>();
tradeVolumeProperty = new SimpleObjectProperty<>();
if (tradeAmount != null) {
tradeAmountProperty.set(tradeAmount);
tradeVolumeProperty.set(getTradeVolume());
}
} }
@Override @Override
protected ProcessModel createProcessModel() { public ProcessModel createProcessModel() {
return new OffererProcessModel(); return new OffererProcessModel();
} }
@Override
public void createProtocol() {
protocol = new OffererProtocol(this);
}
public void onFiatPaymentStarted() {
assert protocol != null;
((OffererProtocol) protocol).onFiatPaymentStarted();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter only
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public ReadOnlyObjectProperty<OffererProcessState> processStateProperty() {
return processStateProperty;
}
@Override
public ReadOnlyObjectProperty<OffererLifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
}
public OffererProcessModel getProcessModel() {
return (OffererProcessModel) processModel;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setProcessState(OffererProcessState processState) {
this.processState = processState;
processStateProperty.set(processState);
switch (processState) {
case EXCEPTION:
disposeProtocol();
setLifeCycleState(OffererLifeCycleState.FAILED);
break;
}
}
public void setLifeCycleState(OffererLifeCycleState lifeCycleState) {
switch (lifeCycleState) {
case FAILED:
disposeProtocol();
break;
case COMPLETED:
disposeProtocol();
break;
}
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects // Getter/Setter for Mutable objects
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public OffererProcessModel getProcessModel() {
return (OffererProcessModel) processModel;
}
public void setTradingPeer(Peer tradingPeer) { public void setTradingPeer(Peer tradingPeer) {
this.tradingPeer = tradingPeer; this.tradingPeer = tradingPeer;
} }
@ -230,30 +134,27 @@ public class OffererTrade extends Trade implements Serializable {
return null; return null;
} }
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return tradeAmountProperty;
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return tradeVolumeProperty;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Protected // Protected
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
protected void setupConfidenceListener() { protected void initAmountProperty() {
assert depositTx != null; tradeAmountProperty = new SimpleObjectProperty<>();
TransactionConfidence transactionConfidence = depositTx.getConfidence(); tradeVolumeProperty = new SimpleObjectProperty<>();
ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1);
Futures.addCallback(future, new FutureCallback<TransactionConfidence>() {
@Override
public void onSuccess(TransactionConfidence result) {
if (processState.ordinal() < OffererProcessState.DEPOSIT_CONFIRMED.ordinal())
setProcessState(OffererProcessState.DEPOSIT_CONFIRMED);
}
@Override if (tradeAmount != null) {
public void onFailure(@NotNull Throwable t) { tradeAmountProperty.set(tradeAmount);
t.printStackTrace(); tradeVolumeProperty.set(getTradeVolume());
log.error(t.getMessage());
Throwables.propagate(t);
} }
});
} }
@Override @Override
@ -261,8 +162,6 @@ public class OffererTrade extends Trade implements Serializable {
return "OffererTrade{" + return "OffererTrade{" +
"tradeAmount=" + tradeAmount + "tradeAmount=" + tradeAmount +
", tradingPeer=" + tradingPeer + ", tradingPeer=" + tradingPeer +
", processState=" + processState + super.toString();
", lifeCycleState=" + lifeCycleState +
'}';
} }
} }

View file

@ -0,0 +1,161 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.taker.TakerAsBuyerProtocol;
import org.bitcoinj.core.Coin;
import java.io.IOException;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerAsBuyerTrade extends TakerTrade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(TakerAsBuyerTrade.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public enum LifeCycleState implements TakerTrade.LifeCycleState {
PENDING,
COMPLETED,
FAILED
}
public enum ProcessState implements TakerTrade.ProcessState {
UNDEFINED,
TAKE_OFFER_FEE_TX_CREATED,
TAKE_OFFER_FEE_PUBLISHED,
TAKE_OFFER_FEE_PUBLISH_FAILED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
FIAT_PAYMENT_RECEIVED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
EXCEPTION
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public TakerAsBuyerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer,
Storage<? extends TradeList> storage) {
super(offer, tradeAmount, tradingPeer, storage);
log.trace("Created by constructor");
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties();
initAmountProperty();
}
@Override
protected void initStates() {
processState = ProcessState.UNDEFINED;
lifeCycleState = TakerAsBuyerTrade.LifeCycleState.PENDING;
initStateProperties();
}
@Override
public void createProtocol() {
protocol = new TakerAsBuyerProtocol(this);
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void takeAvailableOffer() {
assert protocol instanceof TakerAsBuyerProtocol;
((TakerAsBuyerProtocol) protocol).takeAvailableOffer();
}
public void onFiatPaymentStarted() {
assert protocol instanceof TakerAsBuyerProtocol;
((TakerAsBuyerProtocol) protocol).onFiatPaymentStarted();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void setProcessState(Trade.ProcessState processState) {
super.setProcessState(processState);
switch ((ProcessState) processState) {
case EXCEPTION:
disposeProtocol();
setLifeCycleState(TakerAsBuyerTrade.LifeCycleState.FAILED);
break;
}
}
@Override
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
super.setLifeCycleState(lifeCycleState);
switch ((LifeCycleState) lifeCycleState) {
case FAILED:
disposeProtocol();
break;
case COMPLETED:
disposeProtocol();
break;
}
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(ProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void handleConfidenceResult() {
if (((ProcessState) processState).ordinal() < ProcessState.DEPOSIT_CONFIRMED.ordinal())
setProcessState(ProcessState.DEPOSIT_CONFIRMED);
}
}

View file

@ -0,0 +1,164 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.taker.TakerAsSellerProtocol;
import org.bitcoinj.core.Coin;
import java.io.IOException;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerAsSellerTrade extends TakerTrade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(TakerAsSellerTrade.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public enum LifeCycleState implements TakerTrade.LifeCycleState {
PENDING,
COMPLETED,
FAILED
}
public enum ProcessState implements TakerTrade.ProcessState {
UNDEFINED,
TAKE_OFFER_FEE_TX_CREATED,
TAKE_OFFER_FEE_PUBLISHED,
TAKE_OFFER_FEE_PUBLISH_FAILED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
FIAT_PAYMENT_RECEIVED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
EXCEPTION
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public TakerAsSellerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer,
Storage<? extends TradeList> storage) {
super(offer, tradeAmount, tradingPeer, storage);
log.trace("Created by constructor");
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties();
initAmountProperty();
}
@Override
protected void initStates() {
processState = ProcessState.UNDEFINED;
lifeCycleState = TakerAsSellerTrade.LifeCycleState.PENDING;
initStateProperties();
}
@Override
public void createProtocol() {
protocol = new TakerAsSellerProtocol(this);
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void takeAvailableOffer() {
assert protocol instanceof TakerAsSellerProtocol;
((TakerAsSellerProtocol) protocol).takeAvailableOffer();
}
public void onFiatPaymentReceived() {
assert protocol instanceof TakerAsSellerProtocol;
((TakerAsSellerProtocol) protocol).onFiatPaymentReceived();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void setProcessState(Trade.ProcessState processState) {
ProcessState state = (ProcessState) processState;
this.processState = processState;
processStateProperty.set(processState);
switch (state) {
case EXCEPTION:
disposeProtocol();
setLifeCycleState(TakerAsSellerTrade.LifeCycleState.FAILED);
break;
}
}
@Override
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
LifeCycleState state = (LifeCycleState) lifeCycleState;
switch (state) {
case FAILED:
disposeProtocol();
break;
case COMPLETED:
disposeProtocol();
break;
}
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(ProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void handleConfidenceResult() {
if (((ProcessState) processState).ordinal() < ProcessState.DEPOSIT_CONFIRMED.ordinal())
setProcessState(ProcessState.DEPOSIT_CONFIRMED);
}
}

View file

@ -21,18 +21,11 @@ import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.ProcessModel; import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.trade.protocol.trade.taker.TakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel; import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
@ -40,12 +33,10 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class TakerTrade extends Trade implements Serializable { public abstract class TakerTrade extends Trade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -56,28 +47,10 @@ public class TakerTrade extends Trade implements Serializable {
// Enum // Enum
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public enum TakerLifeCycleState implements LifeCycleState { public interface LifeCycleState extends Trade.LifeCycleState {
PENDING,
COMPLETED,
FAILED
} }
public enum TakerProcessState implements ProcessState { public interface ProcessState extends Trade.ProcessState {
UNDEFINED,
TAKE_OFFER_FEE_TX_CREATED,
TAKE_OFFER_FEE_PUBLISHED,
TAKE_OFFER_FEE_PUBLISH_FAILED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
FIAT_PAYMENT_RECEIVED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
EXCEPTION
} }
@ -85,24 +58,18 @@ public class TakerTrade extends Trade implements Serializable {
// Fields // Fields
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Transient/Immutable
transient private ObjectProperty<TakerProcessState> processStateProperty;
transient private ObjectProperty<TakerLifeCycleState> lifeCycleStateProperty;
// Immutable // Immutable
private final Coin tradeAmount; protected final Coin tradeAmount;
private final Peer tradingPeer; protected final Peer tradingPeer;
transient protected ObjectProperty<Coin> tradeAmountProperty;
// Mutable transient protected ObjectProperty<Fiat> tradeVolumeProperty;
private TakerProcessState processState;
private TakerLifeCycleState lifeCycleState;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public TakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, protected TakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer,
Storage<? extends TradeList> storage) { Storage<? extends TradeList> storage) {
super(offer, storage); super(offer, storage);
log.trace("Created by constructor"); log.trace("Created by constructor");
@ -110,53 +77,24 @@ public class TakerTrade extends Trade implements Serializable {
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
this.tradingPeer = tradingPeer; this.tradingPeer = tradingPeer;
processState = TakerProcessState.UNDEFINED; initStates();
lifeCycleState = TakerLifeCycleState.PENDING; initStateProperties();
initAmountProperty();
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
} }
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form."); log.trace("Created from serialized form.");
processStateProperty = new SimpleObjectProperty<>(processState); initStateProperties();
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState); initAmountProperty();
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
} }
@Override @Override
protected ProcessModel createProcessModel() { public ProcessModel createProcessModel() {
return new TakerProcessModel(); return new TakerProcessModel();
} }
@Override
public void createProtocol() {
protocol = new TakerProtocol(this);
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void takeAvailableOffer() {
assert processModel != null;
((TakerProtocol) protocol).takeAvailableOffer();
}
public void onFiatPaymentReceived() {
assert protocol != null;
((TakerProtocol) protocol).onFiatPaymentReceived();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getter only // Getter only
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -175,70 +113,26 @@ public class TakerTrade extends Trade implements Serializable {
return tradingPeer; return tradingPeer;
} }
@Override
public ReadOnlyObjectProperty<TakerProcessState> processStateProperty() {
return processStateProperty;
}
@Override
public ReadOnlyObjectProperty<TakerLifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
}
public TakerProcessModel getProcessModel() { public TakerProcessModel getProcessModel() {
return (TakerProcessModel) processModel; return (TakerProcessModel) processModel;
} }
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
/////////////////////////////////////////////////////////////////////////////////////////// return tradeAmountProperty;
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setLifeCycleState(TakerLifeCycleState lifeCycleState) {
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
} }
public void setProcessState(TakerProcessState processState) { public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
this.processState = processState; return tradeVolumeProperty;
processStateProperty.set(processState);
if (processState == TakerProcessState.EXCEPTION) {
setLifeCycleState(TakerLifeCycleState.FAILED);
disposeProtocol();
} }
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(TakerTrade.TakerProcessState.EXCEPTION);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Protected // Protected
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
protected void setupConfidenceListener() { protected void initAmountProperty() {
assert depositTx != null; tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
TransactionConfidence transactionConfidence = depositTx.getConfidence(); tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1);
Futures.addCallback(future, new FutureCallback<TransactionConfidence>() {
@Override
public void onSuccess(TransactionConfidence result) {
if (processState.ordinal() < TakerProcessState.DEPOSIT_CONFIRMED.ordinal())
setProcessState(TakerProcessState.DEPOSIT_CONFIRMED);
}
@Override
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
Throwables.propagate(t);
}
});
} }
@Override @Override
@ -246,8 +140,6 @@ public class TakerTrade extends Trade implements Serializable {
return "TakerTrade{" + return "TakerTrade{" +
"tradeAmount=" + tradeAmount + "tradeAmount=" + tradeAmount +
", tradingPeer=" + tradingPeer + ", tradingPeer=" + tradingPeer +
", processState=" + processState + super.toString();
", lifeCycleState=" + lifeCycleState +
'}';
} }
} }

View file

@ -33,8 +33,14 @@ import io.bitsquare.user.User;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
@ -45,6 +51,9 @@ import javax.annotation.Nullable;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -64,10 +73,10 @@ abstract public class Trade extends Model implements Serializable {
// Interfaces // Interfaces
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
interface ProcessState { public interface LifeCycleState {
} }
public interface LifeCycleState { public interface ProcessState {
} }
@ -76,6 +85,9 @@ abstract public class Trade extends Model implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Transient/Immutable // Transient/Immutable
transient protected ObjectProperty<ProcessState> processStateProperty;
transient protected ObjectProperty<LifeCycleState> lifeCycleStateProperty;
transient private Storage<? extends TradeList> storage; transient private Storage<? extends TradeList> storage;
transient protected Protocol protocol; transient protected Protocol protocol;
@ -85,6 +97,8 @@ abstract public class Trade extends Model implements Serializable {
protected final ProcessModel processModel; protected final ProcessModel processModel;
// Mutable // Mutable
protected ProcessState processState;
protected LifeCycleState lifeCycleState;
private MailboxMessage mailboxMessage; private MailboxMessage mailboxMessage;
protected Transaction depositTx; protected Transaction depositTx;
private Contract contract; private Contract contract;
@ -96,15 +110,13 @@ abstract public class Trade extends Model implements Serializable {
// Transient/Mutable // Transient/Mutable
transient private String errorMessage; transient private String errorMessage;
transient private Throwable throwable; transient private Throwable throwable;
transient protected ObjectProperty<Coin> tradeAmountProperty;
transient protected ObjectProperty<Fiat> tradeVolumeProperty;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
Trade(Offer offer, Storage<? extends TradeList> storage) { protected Trade(Offer offer, Storage<? extends TradeList> storage) {
log.trace("Created by constructor"); log.trace("Created by constructor");
this.offer = offer; this.offer = offer;
this.storage = storage; this.storage = storage;
@ -141,18 +153,6 @@ abstract public class Trade extends Model implements Serializable {
protocol.setMailboxMessage(mailboxMessage); protocol.setMailboxMessage(mailboxMessage);
} }
public void setStorage(Storage<? extends TradeList> storage) {
this.storage = storage;
}
abstract protected ProcessModel createProcessModel();
abstract protected void createProtocol();
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
// The deserialized tx has not actual confidence data, so we need to get the fresh one from the wallet. // The deserialized tx has not actual confidence data, so we need to get the fresh one from the wallet.
public void updateDepositTxFromWallet(TradeWalletService tradeWalletService) { public void updateDepositTxFromWallet(TradeWalletService tradeWalletService) {
@ -163,6 +163,7 @@ abstract public class Trade extends Model implements Serializable {
public void setDepositTx(Transaction tx) { public void setDepositTx(Transaction tx) {
this.depositTx = tx; this.depositTx = tx;
setupConfidenceListener(); setupConfidenceListener();
storage.queueUpForSave();
} }
public void disposeProtocol() { public void disposeProtocol() {
@ -180,7 +181,57 @@ abstract public class Trade extends Model implements Serializable {
storage.queueUpForSave(); storage.queueUpForSave();
} }
protected abstract void setupConfidenceListener(); public void setStorage(Storage<? extends TradeList> storage) {
this.storage = storage;
}
public void setProcessState(Trade.ProcessState processState) {
this.processState = processState;
processStateProperty.set(processState);
storage.queueUpForSave();
}
public void setLifeCycleState(Trade.LifeCycleState lifeCycleState) {
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
storage.queueUpForSave();
}
protected void setupConfidenceListener() {
if (depositTx != null) {
TransactionConfidence transactionConfidence = depositTx.getConfidence();
ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1);
Futures.addCallback(future, new FutureCallback<TransactionConfidence>() {
@Override
public void onSuccess(TransactionConfidence result) {
handleConfidenceResult();
}
@Override
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
Throwables.propagate(t);
}
});
}
}
abstract protected void createProtocol();
abstract protected void initAmountProperty();
abstract protected void handleConfidenceResult();
abstract protected void initStates();
abstract protected ProcessModel createProcessModel();
protected void initStateProperties() {
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -224,24 +275,19 @@ abstract public class Trade extends Model implements Serializable {
return offer.getSecurityDeposit(); return offer.getSecurityDeposit();
} }
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return tradeAmountProperty;
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return tradeVolumeProperty;
}
@Nullable @Nullable
abstract public Coin getTradeAmount(); abstract public Coin getTradeAmount();
@Nullable @Nullable
abstract public Fiat getTradeVolume(); abstract public Fiat getTradeVolume();
abstract public ReadOnlyObjectProperty<? extends ProcessState> processStateProperty(); public ReadOnlyObjectProperty<? extends ProcessState> processStateProperty() {
return processStateProperty;
}
abstract public ReadOnlyObjectProperty<? extends LifeCycleState> lifeCycleStateProperty(); public ReadOnlyObjectProperty<? extends LifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -314,18 +360,21 @@ abstract public class Trade extends Model implements Serializable {
@Override @Override
public String toString() { public String toString() {
return "Trade{" + return ", protocol=" + protocol +
"throwable=" + throwable +
", offer=" + offer + ", offer=" + offer +
", date=" + date + ", date=" + date +
", processModel=" + processModel +
", processState=" + processState +
", lifeCycleState=" + lifeCycleState +
", mailboxMessage=" + mailboxMessage + ", mailboxMessage=" + mailboxMessage +
", depositTx=" + depositTx + ", depositTx=" + depositTx +
", contract=" + contract + ", contract=" + contract +
", contractAsJson='" + contractAsJson + '\'' + ", contractAsJson='" + contractAsJson + '\'' +
", takerContractSignature='" + takerContractSignature + '\'' + ", takerContractSignature='" + takerContractSignature + '\'' +
", offererContractSignature='" + offererContractSignature + '\'' + ", offererContractSignature='" + offererContractSignature + '\'' +
", payoutTx=" + payoutTx +
", errorMessage='" + errorMessage + '\'' + ", errorMessage='" + errorMessage + '\'' +
", processModel=" + processModel + ", throwable=" + throwable +
'}'; '}';
} }
} }

View file

@ -56,6 +56,7 @@ import com.google.common.util.concurrent.FutureCallback;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -90,7 +91,7 @@ public class TradeManager {
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>(); private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
private final Storage<TradeList> pendingTradesStorage; private final Storage<TradeList> pendingTradesStorage;
private final Storage<TradeList> openOfferTradesStorage; private final Storage<TradeList> openOfferTradesStorage;
private final TradeList<OffererTrade> openOfferTrades; private final TradeList<OffererAsBuyerTrade> openOfferTrades;
private final TradeList<Trade> pendingTrades; private final TradeList<Trade> pendingTrades;
private final TradeList<Trade> closedTrades; private final TradeList<Trade> closedTrades;
@ -149,25 +150,43 @@ public class TradeManager {
// When all services are initialized we create the protocols for our open offers and persisted pendingTrades // When all services are initialized we create the protocols for our open offers and persisted pendingTrades
// OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early. // OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early.
public void onAllServicesInitialized() { public void onAllServicesInitialized() {
for (OffererTrade offererTrade : openOfferTrades) { for (OffererAsBuyerTrade OffererAsBuyerTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer(); Offer offer = OffererAsBuyerTrade.getOffer();
// We add own offers to offerbook when we go online again // We add own offers to offerbook when we go online again
offerBookService.addOffer(offer, offerBookService.addOffer(offer,
() -> log.debug("Successful removed open offer from DHT"), () -> log.debug("Successful removed open offer from DHT"),
(message, throwable) -> log.error("Remove open offer from DHT failed. " + message)); (message, throwable) -> log.error("Remove open offer from DHT failed. " + message));
setupDepositPublishedListener(offererTrade); setupDepositPublishedListener(OffererAsBuyerTrade);
offererTrade.setStorage(openOfferTradesStorage); OffererAsBuyerTrade.setStorage(openOfferTradesStorage);
initTrade(offererTrade); initTrade(OffererAsBuyerTrade);
} }
List<Trade> failedTrades = new ArrayList<>();
for (Trade trade : pendingTrades) { for (Trade trade : pendingTrades) {
// We continue an interrupted trade. // We continue an interrupted trade.
// TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to // TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to
// continue the trade, but that might fail. // continue the trade, but that might fail.
boolean failed = false;
if (trade instanceof TakerAsSellerTrade) {
failed = trade.lifeCycleState == TakerAsSellerTrade.LifeCycleState.FAILED;
}
else if (trade instanceof TakerAsBuyerTrade) {
failed = trade.lifeCycleState == TakerAsBuyerTrade.LifeCycleState.FAILED;
}
if (failed) {
failedTrades.add(trade);
}
else {
trade.setStorage(pendingTradesStorage); trade.setStorage(pendingTradesStorage);
trade.updateDepositTxFromWallet(tradeWalletService); trade.updateDepositTxFromWallet(tradeWalletService);
initTrade(trade); initTrade(trade);
} }
}
for (Trade trade : failedTrades) {
pendingTrades.remove(trade);
closedTrades.add(trade);
}
// if there are messages in our mailbox we apply it and remove them from the DHT // if there are messages in our mailbox we apply it and remove them from the DHT
mailboxService.getAllMessages(user.getP2PSigPubKey(), mailboxService.getAllMessages(user.getP2PSigPubKey(),
@ -210,8 +229,8 @@ public class TradeManager {
log.debug("shutDown"); log.debug("shutDown");
shutDownRequested = true; shutDownRequested = true;
// we remove own offers form offerbook when we go offline // we remove own offers form offerbook when we go offline
for (OffererTrade offererTrade : openOfferTrades) { for (OffererAsBuyerTrade OffererAsBuyerTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer(); Offer offer = OffererAsBuyerTrade.getOffer();
offerBookService.removeOfferAtShutDown(offer); offerBookService.removeOfferAtShutDown(offer);
} }
} }
@ -258,23 +277,23 @@ public class TradeManager {
} }
private void handlePlaceOfferResult(Transaction transaction, Offer offer, TransactionResultHandler resultHandler) { private void handlePlaceOfferResult(Transaction transaction, Offer offer, TransactionResultHandler resultHandler) {
OffererTrade offererTrade = new OffererTrade(offer, openOfferTradesStorage); OffererAsBuyerTrade offererAsBuyerTrade = new OffererAsBuyerTrade(offer, openOfferTradesStorage);
openOfferTrades.add(offererTrade); openOfferTrades.add(offererAsBuyerTrade);
initTrade(offererTrade); initTrade(offererAsBuyerTrade);
setupDepositPublishedListener(offererTrade); setupDepositPublishedListener(offererAsBuyerTrade);
resultHandler.handleResult(transaction); resultHandler.handleResult(transaction);
} }
private void setupDepositPublishedListener(OffererTrade offererTrade) { private void setupDepositPublishedListener(OffererAsBuyerTrade offererAsBuyerTrade) {
offererTrade.processStateProperty().addListener((ov, oldValue, newValue) -> { offererAsBuyerTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("offererTrade state = " + newValue); log.debug("OffererAsBuyerTrade state = " + newValue);
if (newValue == OffererTrade.OffererProcessState.DEPOSIT_PUBLISHED) { if (newValue == OffererAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED) {
removeOpenOffer(offererTrade.getOffer(), removeOpenOffer(offererAsBuyerTrade.getOffer(),
() -> log.debug("remove offer was successful"), () -> log.debug("remove offer was successful"),
log::error, log::error,
false); false);
pendingTrades.add(offererTrade); pendingTrades.add(offererAsBuyerTrade);
offererTrade.setStorage(pendingTradesStorage); offererAsBuyerTrade.setStorage(pendingTradesStorage);
} }
}); });
} }
@ -290,15 +309,15 @@ public class TradeManager {
offerBookService.removeOffer(offer, offerBookService.removeOffer(offer,
() -> { () -> {
offer.setState(Offer.State.REMOVED); offer.setState(Offer.State.REMOVED);
Optional<OffererTrade> offererTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny(); Optional<OffererAsBuyerTrade> OffererAsBuyerTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny();
if (offererTradeOptional.isPresent()) { if (OffererAsBuyerTradeOptional.isPresent()) {
OffererTrade offererTrade = offererTradeOptional.get(); OffererAsBuyerTrade offererAsBuyerTrade = OffererAsBuyerTradeOptional.get();
openOfferTrades.remove(offererTrade); openOfferTrades.remove(offererAsBuyerTrade);
if (isCancelRequest) { if (isCancelRequest) {
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_CANCELED); offererAsBuyerTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_CANCELED);
closedTrades.add(offererTrade); closedTrades.add(offererAsBuyerTrade);
offererTrade.disposeProtocol(); offererAsBuyerTrade.disposeProtocol();
} }
} }
@ -351,7 +370,7 @@ public class TradeManager {
takeOfferResultHandler) { takeOfferResultHandler) {
disposeCheckOfferAvailabilityRequest(offer); disposeCheckOfferAvailabilityRequest(offer);
if (offer.getState() == Offer.State.AVAILABLE) { if (offer.getState() == Offer.State.AVAILABLE) {
TakerTrade takerTrade = new TakerTrade(offer, amount, model.getPeer(), pendingTradesStorage); TakerAsSellerTrade takerTrade = new TakerAsSellerTrade(offer, amount, model.getPeer(), pendingTradesStorage);
initTrade(takerTrade); initTrade(takerTrade);
pendingTrades.add(takerTrade); pendingTrades.add(takerTrade);
takerTrade.takeAvailableOffer(); takerTrade.takeAvailableOffer();
@ -371,7 +390,7 @@ public class TradeManager {
// TODO handle overpaid securityDeposit // TODO handle overpaid securityDeposit
Coin amountToWithdraw = trade.getSecurityDeposit(); Coin amountToWithdraw = trade.getSecurityDeposit();
assert trade.getTradeAmount() != null; assert trade.getTradeAmount() != null;
if (trade instanceof OffererTrade) if (trade instanceof OffererAsBuyerTrade)
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount()); amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() { FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@ -379,10 +398,10 @@ public class TradeManager {
public void onSuccess(@javax.annotation.Nullable Transaction transaction) { public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) { if (transaction != null) {
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString()); log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
if (trade instanceof OffererTrade) if (trade instanceof OffererAsBuyerTrade)
((OffererTrade) trade).setLifeCycleState(OffererTrade.OffererLifeCycleState.COMPLETED); ((OffererAsBuyerTrade) trade).setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.COMPLETED);
else else
((TakerTrade) trade).setLifeCycleState(TakerTrade.TakerLifeCycleState.COMPLETED); ((TakerAsSellerTrade) trade).setLifeCycleState(TakerAsSellerTrade.LifeCycleState.COMPLETED);
pendingTrades.remove(trade); pendingTrades.remove(trade);
closedTrades.add(trade); closedTrades.add(trade);
@ -421,7 +440,7 @@ public class TradeManager {
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public ObservableList<OffererTrade> getOpenOfferTrades() { public ObservableList<OffererAsBuyerTrade> getOpenOfferTrades() {
return openOfferTrades.getObservableList(); return openOfferTrades.getObservableList();
} }

View file

@ -0,0 +1,34 @@
/*
* 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.messages;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConfirmReserveOfferMessage extends TradeMessage implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ConfirmReserveOfferMessage.class);
public ConfirmReserveOfferMessage(String tradeId) {
super(tradeId);
}
}

View file

@ -30,20 +30,20 @@ public class FiatTransferStartedMessage extends TradeMessage implements MailboxM
// That object is sent over the wire, so we need to take care of version compatibility. // That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public final byte[] offererSignature; public final byte[] buyerSignature;
public final Coin offererPayoutAmount; public final Coin offererPayoutAmount;
public final Coin takerPayoutAmount; public final Coin takerPayoutAmount;
public final String offererPayoutAddress; public final String buyerPayoutAddress;
public FiatTransferStartedMessage(String tradeId, public FiatTransferStartedMessage(String tradeId,
byte[] offererSignature, byte[] buyerSignature,
Coin offererPayoutAmount, Coin offererPayoutAmount,
Coin takerPayoutAmount, Coin takerPayoutAmount,
String offererPayoutAddress) { String buyerPayoutAddress) {
super(tradeId); super(tradeId);
this.offererSignature = offererSignature; this.buyerSignature = buyerSignature;
this.offererPayoutAmount = offererPayoutAmount; this.offererPayoutAmount = offererPayoutAmount;
this.takerPayoutAmount = takerPayoutAmount; this.takerPayoutAmount = takerPayoutAmount;
this.offererPayoutAddress = offererPayoutAddress; this.buyerPayoutAddress = buyerPayoutAddress;
} }
} }

View file

@ -0,0 +1,62 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.messages;
import io.bitsquare.fiat.FiatAccount;
import org.bitcoinj.core.TransactionOutput;
import java.io.Serializable;
import java.security.PublicKey;
import java.util.List;
import javax.annotation.concurrent.Immutable;
@Immutable
public class RequestPayDepositMessage extends TradeMessage implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = 1L;
public final List<TransactionOutput> buyerConnectedOutputsForAllInputs;
public final List<TransactionOutput> buyerOutputs;
public final byte[] buyerTradeWalletPubKey;
public final PublicKey buyerP2PSigPublicKey;
public final PublicKey buyerP2PEncryptPublicKey;
public final FiatAccount buyerFiatAccount;
public final String buyerAccountId;
public RequestPayDepositMessage(String tradeId,
List<TransactionOutput> buyerConnectedOutputsForAllInputs,
List<TransactionOutput> buyerOutputs,
byte[] buyerTradeWalletPubKey,
PublicKey buyerP2PSigPublicKey,
PublicKey buyerP2PEncryptPublicKey,
FiatAccount buyerFiatAccount,
String buyerAccountId) {
super(tradeId);
this.buyerP2PSigPublicKey = buyerP2PSigPublicKey;
this.buyerP2PEncryptPublicKey = buyerP2PEncryptPublicKey;
this.buyerConnectedOutputsForAllInputs = buyerConnectedOutputsForAllInputs;
this.buyerOutputs = buyerOutputs;
this.buyerTradeWalletPubKey = buyerTradeWalletPubKey;
this.buyerFiatAccount = buyerFiatAccount;
this.buyerAccountId = buyerAccountId;
}
}

View file

@ -1,62 +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.messages;
import io.bitsquare.fiat.FiatAccount;
import org.bitcoinj.core.TransactionOutput;
import java.io.Serializable;
import java.security.PublicKey;
import java.util.List;
import javax.annotation.concurrent.Immutable;
@Immutable
public class RequestTakerDepositPaymentMessage extends TradeMessage implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = 1L;
public final List<TransactionOutput> offererConnectedOutputsForAllInputs;
public final List<TransactionOutput> offererOutputs;
public final byte[] offererTradeWalletPubKey;
public final PublicKey offererP2PSigPublicKey;
public final PublicKey offererP2PEncryptPublicKey;
public final FiatAccount offererFiatAccount;
public final String offererAccountId;
public RequestTakerDepositPaymentMessage(String tradeId,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs,
byte[] offererTradeWalletPubKey,
PublicKey offererP2PSigPublicKey,
PublicKey offererP2PEncryptPublicKey,
FiatAccount offererFiatAccount,
String offererAccountId) {
super(tradeId);
this.offererP2PSigPublicKey = offererP2PSigPublicKey;
this.offererP2PEncryptPublicKey = offererP2PEncryptPublicKey;
this.offererConnectedOutputsForAllInputs = offererConnectedOutputsForAllInputs;
this.offererOutputs = offererOutputs;
this.offererTradeWalletPubKey = offererTradeWalletPubKey;
this.offererFiatAccount = offererFiatAccount;
this.offererAccountId = offererAccountId;
}
}

View file

@ -23,7 +23,7 @@ import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.MessageHandler; import io.bitsquare.p2p.MessageHandler;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.protocol.Protocol; import io.bitsquare.trade.protocol.Protocol;
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage; import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage; import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
@ -32,17 +32,17 @@ import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage; import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel; import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CommitPayoutTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCommitsPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateAndSignPayoutTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateOffererDepositTxInputs; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendRequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendFiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsRequestSellerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSignsAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract; import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererVerifiesAndSignsContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
@ -51,21 +51,21 @@ import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
public class OffererProtocol implements Protocol { public class OffererAsBuyerProtocol implements Protocol {
private static final Logger log = LoggerFactory.getLogger(OffererProtocol.class); private static final Logger log = LoggerFactory.getLogger(OffererAsBuyerProtocol.class);
private final MessageHandler messageHandler; private MessageHandler messageHandler;
private final OffererTrade offererTrade; private final OffererAsBuyerTrade offererAsBuyerTrade;
private final OffererProcessModel offererTradeProcessModel; private final OffererProcessModel offererTradeProcessModel;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public OffererProtocol(OffererTrade model) { public OffererAsBuyerProtocol(OffererAsBuyerTrade model) {
log.debug("New OffererProtocol " + this); log.debug("New OffererProtocol " + this);
this.offererTrade = model; this.offererAsBuyerTrade = model;
offererTradeProcessModel = offererTrade.getProcessModel(); offererTradeProcessModel = offererAsBuyerTrade.getProcessModel();
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
offererTradeProcessModel.getMessageService().addMessageHandler(messageHandler); offererTradeProcessModel.getMessageService().addMessageHandler(messageHandler);
@ -90,7 +90,10 @@ public class OffererProtocol implements Protocol {
public void cleanup() { public void cleanup() {
log.debug("cleanup " + this); log.debug("cleanup " + this);
if (messageHandler != null) {
offererTradeProcessModel.getMessageService().removeMessageHandler(messageHandler); offererTradeProcessModel.getMessageService().removeMessageHandler(messageHandler);
messageHandler = null;
}
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -106,7 +109,7 @@ public class OffererProtocol implements Protocol {
// to take the // to take the
// offer // offer
// at the same time // at the same time
boolean isOfferOpen = offererTrade.lifeCycleStateProperty().get() == OffererTrade.OffererLifeCycleState.OFFER_OPEN; boolean isOfferOpen = offererAsBuyerTrade.lifeCycleStateProperty().get() == OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN;
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offererTradeProcessModel.getId(), isOfferOpen); ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offererTradeProcessModel.getId(), isOfferOpen);
offererTradeProcessModel.getMessageService().sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() { offererTradeProcessModel.getMessageService().sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
@Override @Override
@ -131,16 +134,17 @@ public class OffererProtocol implements Protocol {
private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) { private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) {
checkTradeId(offererTradeProcessModel.getId(), tradeMessage); checkTradeId(offererTradeProcessModel.getId(), tradeMessage);
offererTradeProcessModel.setTradeMessage(tradeMessage); offererTradeProcessModel.setTradeMessage(tradeMessage);
offererTrade.setTradingPeer(taker); offererAsBuyerTrade.setTradingPeer(taker);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_RESERVED);
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade, offererAsBuyerTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_RESERVED);
TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> log.debug("taskRunner at handleRequestDepositTxInputsMessage completed"), () -> log.debug("taskRunner at handleRequestDepositTxInputsMessage completed"),
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
ProcessRequestDepositTxInputsMessage.class, OffererProcessRequestDepositTxInputsMessage.class,
CreateOffererDepositTxInputs.class, OffererCreatesDepositTxInputs.class,
SendRequestTakerDepositPaymentMessage.class OffererSendsRequestSellerDepositPaymentMessage.class
); );
taskRunner.run(); taskRunner.run();
} }
@ -148,15 +152,15 @@ public class OffererProtocol implements Protocol {
private void handleRequestPublishDepositTxMessage(RequestPublishDepositTxMessage tradeMessage) { private void handleRequestPublishDepositTxMessage(RequestPublishDepositTxMessage tradeMessage) {
offererTradeProcessModel.setTradeMessage(tradeMessage); offererTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade, TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> log.debug("taskRunner at handleRequestPublishDepositTxMessage completed"), () -> log.debug("taskRunner at handleRequestPublishDepositTxMessage completed"),
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
ProcessRequestPublishDepositTxMessage.class, OffererProcessRequestPublishDepositTxMessage.class,
VerifyTakerAccount.class, VerifyTakerAccount.class,
VerifyAndSignContract.class, OffererVerifiesAndSignsContract.class,
SignAndPublishDepositTx.class, OffererSignsAndPublishDepositTx.class,
SendDepositTxPublishedMessage.class OffererSendsDepositTxPublishedMessage.class
); );
taskRunner.run(); taskRunner.run();
} }
@ -168,13 +172,13 @@ public class OffererProtocol implements Protocol {
// User clicked the "bank transfer started" button // User clicked the "bank transfer started" button
public void onFiatPaymentStarted() { public void onFiatPaymentStarted() {
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade, TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> log.debug("taskRunner at handleBankTransferStartedUIEvent completed"), () -> log.debug("taskRunner at handleBankTransferStartedUIEvent completed"),
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
CreateAndSignPayoutTx.class,
VerifyTakeOfferFeePayment.class, VerifyTakeOfferFeePayment.class,
SendFiatTransferStartedMessage.class OffererCreatesAndSignPayoutTx.class,
OffererSendsFiatTransferStartedMessage.class
); );
taskRunner.run(); taskRunner.run();
} }
@ -187,7 +191,7 @@ public class OffererProtocol implements Protocol {
private void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage) { private void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage) {
offererTradeProcessModel.setTradeMessage(tradeMessage); offererTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade, TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> { () -> {
log.debug("taskRunner at handlePayoutTxPublishedMessage completed"); log.debug("taskRunner at handlePayoutTxPublishedMessage completed");
// we are done! // we are done!
@ -195,8 +199,8 @@ public class OffererProtocol implements Protocol {
}, },
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks(ProcessPayoutTxPublishedMessage.class); taskRunner.addTasks(OffererProcessPayoutTxPublishedMessage.class);
taskRunner.addTasks(CommitPayoutTx.class); taskRunner.addTasks(OffererCommitsPayoutTx.class);
taskRunner.run(); taskRunner.run();
} }
@ -211,7 +215,7 @@ public class OffererProtocol implements Protocol {
TradeMessage tradeMessage = (TradeMessage) message; TradeMessage tradeMessage = (TradeMessage) message;
nonEmptyStringOf(tradeMessage.tradeId); nonEmptyStringOf(tradeMessage.tradeId);
if (tradeMessage.tradeId.equals(offererTrade.getId())) { if (tradeMessage.tradeId.equals(offererAsBuyerTrade.getId())) {
if (tradeMessage instanceof RequestIsOfferAvailableMessage) { if (tradeMessage instanceof RequestIsOfferAvailableMessage) {
handleRequestIsOfferAvailableMessage((RequestIsOfferAvailableMessage) tradeMessage, sender); handleRequestIsOfferAvailableMessage((RequestIsOfferAvailableMessage) tradeMessage, sender);
} }

View file

@ -0,0 +1,239 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.MessageHandler;
import io.bitsquare.p2p.Peer;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.protocol.Protocol;
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCommitDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignsContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignsDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestPayDepositMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSignsAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.*;
public class OffererAsSellerProtocol implements Protocol {
private static final Logger log = LoggerFactory.getLogger(OffererAsSellerProtocol.class);
private final MessageHandler messageHandler;
private final OffererAsSellerTrade offererAsSellerTrade;
private final OffererProcessModel offererTradeProcessModel;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public OffererAsSellerProtocol(OffererAsSellerTrade model) {
log.debug("New OffererProtocol " + this);
this.offererAsSellerTrade = model;
offererTradeProcessModel = offererAsSellerTrade.getProcessModel();
messageHandler = this::handleMessage;
offererTradeProcessModel.getMessageService().addMessageHandler(messageHandler);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
public void setMailboxMessage(MailboxMessage mailboxMessage) {
log.debug("setMailboxMessage " + mailboxMessage);
// Might be called twice, so check that its only processed once
/* if (offererTradeProcessModel.getMailboxMessage() == null) {
offererTradeProcessModel.setMailboxMessage(mailboxMessage);
if (mailboxMessage instanceof PayoutTxPublishedMessage) {
handlePayoutTxPublishedMessage((PayoutTxPublishedMessage) mailboxMessage);
}
}*/
}
public void cleanup() {
log.debug("cleanup " + this);
offererTradeProcessModel.getMessageService().removeMessageHandler(messageHandler);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// IsOfferAvailable
///////////////////////////////////////////////////////////////////////////////////////////
private void handle(RequestIsOfferAvailableMessage tradeMessage, Peer sender) {
try {
checkTradeId(offererTradeProcessModel.getId(), tradeMessage);
// We don't store anything in the offererTradeProcessModel as we might be in a trade process and receive that request from another peer who wants
// to take the
// offer
// at the same time
boolean isOfferOpen = offererAsSellerTrade.lifeCycleStateProperty().get() == OffererAsSellerTrade.LifeCycleState.OFFER_OPEN;
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offererTradeProcessModel.getId(), isOfferOpen);
offererTradeProcessModel.getMessageService().sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
@Override
public void handleResult() {
// Offerer does not do anything at that moment. Peer might only watch the offer and does not start a trade.
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
}
@Override
public void handleFault() {
log.warn("Sending ReportOfferAvailabilityMessage failed.");
}
});
} catch (Throwable t) {
// We don't handle the error as we might be in a trade process with another trader
t.printStackTrace();
log.warn("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage());
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Trade
///////////////////////////////////////////////////////////////////////////////////////////
private void handle(RequestPayDepositMessage tradeMessage) {
offererTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<OffererAsSellerTrade> taskRunner = new TaskRunner<>(offererAsSellerTrade,
() -> log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
OffererProcessRequestPayDepositMessage.class,
VerifyTakerAccount.class,
OffererCreatesAndSignsContract.class,
OffererCreatesAndSignsDepositTx.class,
OffererSendsRequestPublishDepositTxMessage.class
);
taskRunner.run();
}
private void handle(DepositTxPublishedMessage tradeMessage) {
offererTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<OffererAsSellerTrade> taskRunner = new TaskRunner<>(offererAsSellerTrade,
() -> log.debug("taskRunner at handleDepositTxPublishedMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
OffererProcessDepositTxPublishedMessage.class,
OffererCommitDepositTx.class
);
taskRunner.run();
}
private void handle(FiatTransferStartedMessage tradeMessage) {
offererTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<OffererAsSellerTrade> taskRunner = new TaskRunner<>(offererAsSellerTrade,
() -> log.debug("taskRunner at handleFiatTransferStartedMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(OffererProcessFiatTransferStartedMessage.class);
taskRunner.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Called from UI
///////////////////////////////////////////////////////////////////////////////////////////
// User clicked the "bank transfer received" button, so we release the funds for pay out
public void onFiatPaymentReceived() {
offererAsSellerTrade.setProcessState(OffererAsSellerTrade.ProcessState.FIAT_PAYMENT_RECEIVED);
TaskRunner<OffererAsSellerTrade> taskRunner = new TaskRunner<>(offererAsSellerTrade,
() -> {
log.debug("taskRunner at handleFiatReceivedUIEvent completed");
// we are done!
offererTradeProcessModel.onComplete();
},
this::handleTaskRunnerFault);
taskRunner.addTasks(
VerifyOfferFeePayment.class,
OffererSignsAndPublishPayoutTx.class,
OffererSendsPayoutTxPublishedMessage.class
);
taskRunner.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Massage dispatcher
///////////////////////////////////////////////////////////////////////////////////////////
private void handleMessage(Message message, Peer sender) {
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName() + " from " + sender);
if (message instanceof TradeMessage) {
TradeMessage tradeMessage = (TradeMessage) message;
nonEmptyStringOf(tradeMessage.tradeId);
if (tradeMessage.tradeId.equals(offererAsSellerTrade.getId())) {
if (tradeMessage instanceof RequestIsOfferAvailableMessage) {
handle((RequestIsOfferAvailableMessage) tradeMessage, sender);
}
else if (tradeMessage instanceof RequestPayDepositMessage) {
handle((RequestPayDepositMessage) tradeMessage);
}
else if (tradeMessage instanceof DepositTxPublishedMessage) {
handle((DepositTxPublishedMessage) tradeMessage);
}
else if (tradeMessage instanceof FiatTransferStartedMessage) {
handle((FiatTransferStartedMessage) tradeMessage);
}
else {
log.error("Incoming tradeMessage not supported. " + tradeMessage);
}
}
}
}
private void handleTaskRunnerFault(String errorMessage) {
log.error(errorMessage);
cleanup();
}
}

View file

@ -24,6 +24,7 @@ import io.bitsquare.offer.Offer;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.crypto.DeterministicKey; import org.bitcoinj.crypto.DeterministicKey;
@ -36,8 +37,6 @@ import java.security.PublicKey;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.annotation.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -57,7 +56,8 @@ public class Offerer implements Serializable {
private Coin payoutAmount; private Coin payoutAmount;
private List<TransactionOutput> connectedOutputsForAllInputs; private List<TransactionOutput> connectedOutputsForAllInputs;
private List<TransactionOutput> outputs; // used to verify amounts with change outputs private List<TransactionOutput> outputs; // used to verify amounts with change outputs
private Transaction preparedDepositTx;
private PublicKey p2pSigPublicKey;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
@ -99,6 +99,10 @@ public class Offerer implements Serializable {
return user.getP2PSigPubKey(); return user.getP2PSigPubKey();
} }
public PublicKey getP2pEncryptPublicKey() {
return user.getP2PEncryptPubKey();
}
public PublicKey getP2pEncryptPubKey() { public PublicKey getP2pEncryptPubKey() {
return user.getP2PEncryptPubKey(); return user.getP2PEncryptPubKey();
} }
@ -124,7 +128,7 @@ public class Offerer implements Serializable {
// Getter/Setter for Mutable objects // Getter/Setter for Mutable objects
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Nullable
public List<TransactionOutput> getOutputs() { public List<TransactionOutput> getOutputs() {
return outputs; return outputs;
} }
@ -133,7 +137,6 @@ public class Offerer implements Serializable {
this.outputs = outputs; this.outputs = outputs;
} }
@Nullable
public byte[] getPayoutTxSignature() { public byte[] getPayoutTxSignature() {
return payoutTxSignature; return payoutTxSignature;
} }
@ -142,7 +145,6 @@ public class Offerer implements Serializable {
this.payoutTxSignature = payoutTxSignature; this.payoutTxSignature = payoutTxSignature;
} }
@Nullable
public Coin getPayoutAmount() { public Coin getPayoutAmount() {
return payoutAmount; return payoutAmount;
} }
@ -151,7 +153,6 @@ public class Offerer implements Serializable {
this.payoutAmount = payoutAmount; this.payoutAmount = payoutAmount;
} }
@Nullable
public List<TransactionOutput> getConnectedOutputsForAllInputs() { public List<TransactionOutput> getConnectedOutputsForAllInputs() {
return connectedOutputsForAllInputs; return connectedOutputsForAllInputs;
} }
@ -160,6 +161,22 @@ public class Offerer implements Serializable {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs; this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
} }
public Transaction getPreparedDepositTx() {
return preparedDepositTx;
}
public void setPreparedDepositTx(Transaction preparedDepositTx) {
this.preparedDepositTx = preparedDepositTx;
}
public PublicKey getP2pSigPublicKey() {
return p2pSigPublicKey;
}
public void setP2pSigPublicKey(PublicKey p2pSigPublicKey) {
this.p2pSigPublicKey = p2pSigPublicKey;
}
@Override @Override
public String toString() { public String toString() {
return "Offerer{" + return "Offerer{" +
@ -172,4 +189,6 @@ public class Offerer implements Serializable {
", outputs=" + outputs + ", outputs=" + outputs +
'}'; '}';
} }
} }

View file

@ -27,6 +27,8 @@ import io.bitsquare.p2p.MessageService;
import io.bitsquare.trade.protocol.trade.ProcessModel; import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import org.bitcoinj.core.Transaction;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
@ -47,6 +49,7 @@ public class OffererProcessModel extends ProcessModel implements Serializable {
// Mutable // Mutable
private String takeOfferFeeTxId; private String takeOfferFeeTxId;
private Transaction payoutTx;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -99,6 +102,13 @@ public class OffererProcessModel extends ProcessModel implements Serializable {
this.takeOfferFeeTxId = takeOfferFeeTxId; this.takeOfferFeeTxId = takeOfferFeeTxId;
} }
public Transaction getPayoutTx() {
return payoutTx;
}
public void setPayoutTx(Transaction payoutTx) {
this.payoutTx = payoutTx;
}
@Override @Override
public String toString() { public String toString() {
@ -108,4 +118,6 @@ public class OffererProcessModel extends ProcessModel implements Serializable {
", takeOfferFeeTxId='" + takeOfferFeeTxId + '\'' + ", takeOfferFeeTxId='" + takeOfferFeeTxId + '\'' +
'}'; '}';
} }
} }

View file

@ -44,7 +44,7 @@ public class Taker implements Serializable {
// Mutable // Mutable
private String accountId; private String accountId;
private FiatAccount fiatAccount; private FiatAccount fiatAccount;
private PublicKey p2pSigPublicKey; private PublicKey p2pSigPubKey;
private PublicKey p2pEncryptPubKey; private PublicKey p2pEncryptPubKey;
private String contractAsJson; private String contractAsJson;
private String contractSignature; private String contractSignature;
@ -53,7 +53,8 @@ public class Taker implements Serializable {
private List<TransactionOutput> connectedOutputsForAllInputs; private List<TransactionOutput> connectedOutputsForAllInputs;
private String payoutAddressString; private String payoutAddressString;
private byte[] tradeWalletPubKey; private byte[] tradeWalletPubKey;
private List<TransactionOutput> outputs;
private byte[] signature;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
@ -89,12 +90,12 @@ public class Taker implements Serializable {
this.fiatAccount = fiatAccount; this.fiatAccount = fiatAccount;
} }
public PublicKey getP2pSigPublicKey() { public PublicKey getP2pSigPubKey() {
return p2pSigPublicKey; return p2pSigPubKey;
} }
public void setP2pSigPublicKey(PublicKey p2pSigPublicKey) { public void setP2pSigPubKey(PublicKey p2pSigPubKey) {
this.p2pSigPublicKey = p2pSigPublicKey; this.p2pSigPubKey = p2pSigPubKey;
} }
public PublicKey getP2pEncryptPubKey() { public PublicKey getP2pEncryptPubKey() {
@ -161,13 +162,28 @@ public class Taker implements Serializable {
this.tradeWalletPubKey = tradeWalletPubKey; this.tradeWalletPubKey = tradeWalletPubKey;
} }
public List<TransactionOutput> getOutputs() {
return outputs;
}
public void setOutputs(List<TransactionOutput> outputs) {
this.outputs = outputs;
}
public byte[] getSignature() {
return signature;
}
public void setSignature(byte[] signature) {
this.signature = signature;
}
@Override @Override
public String toString() { public String toString() {
return "Taker{" + return "Taker{" +
"accountId='" + accountId + '\'' + "accountId='" + accountId + '\'' +
", fiatAccount=" + fiatAccount + ", fiatAccount=" + fiatAccount +
", p2pSigPublicKey=" + p2pSigPublicKey + ", p2pSigPublicKey=" + p2pSigPubKey +
", p2pEncryptPubKey=" + p2pEncryptPubKey + ", p2pEncryptPubKey=" + p2pEncryptPubKey +
", contractAsJson='" + contractAsJson + '\'' + ", contractAsJson='" + contractAsJson + '\'' +
", contractSignature='" + contractSignature + '\'' + ", contractSignature='" + contractSignature + '\'' +
@ -178,4 +194,6 @@ public class Taker implements Serializable {
", tradeWalletPubKey=" + Arrays.toString(tradeWalletPubKey) + ", tradeWalletPubKey=" + Arrays.toString(tradeWalletPubKey) +
'}'; '}';
} }
} }

View file

@ -0,0 +1,50 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererCommitDepositTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCommitDepositTx.class);
public OffererCommitDepositTx(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
// To access tx confidence we need to add that tx into our wallet.
Transaction depositTx = offererTradeProcessModel.getTradeWalletService().commitTx(offererTrade.getDepositTx());
offererTrade.setDepositTx(depositTx);
complete();
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -25,10 +25,10 @@ import org.bitcoinj.core.Transaction;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CommitPayoutTx extends OffererTradeTask { public class OffererCommitsPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(CommitPayoutTx.class); private static final Logger log = LoggerFactory.getLogger(OffererCommitsPayoutTx.class);
public CommitPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererCommitsPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }

View file

@ -18,6 +18,7 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -25,10 +26,10 @@ import org.bitcoinj.core.Coin;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CreateAndSignPayoutTx extends OffererTradeTask { public class OffererCreatesAndSignPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignPayoutTx.class); private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignPayoutTx.class);
public CreateAndSignPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererCreatesAndSignPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -37,10 +38,16 @@ public class CreateAndSignPayoutTx extends OffererTradeTask {
try { try {
assert offererTrade.getTradeAmount() != null; assert offererTrade.getTradeAmount() != null;
Coin securityDeposit = offererTrade.getSecurityDeposit(); Coin securityDeposit = offererTrade.getSecurityDeposit();
Coin offererPayoutAmount = offererTrade.getTradeAmount().add(securityDeposit);
@SuppressWarnings("UnnecessaryLocalVariable") Coin takerPayoutAmount = securityDeposit;
byte[] offererPayoutTxSignature = offererTradeProcessModel.getTradeWalletService().offererCreatesAndSignsPayoutTx( Coin offererPayoutAmount = securityDeposit;
if (offererTrade.getOffer().getDirection() == Offer.Direction.BUY)
offererPayoutAmount = offererPayoutAmount.add(offererTrade.getTradeAmount());
Coin takerPayoutAmount = securityDeposit;
if (offererTrade.getOffer().getDirection() == Offer.Direction.SELL)
takerPayoutAmount = takerPayoutAmount.add(offererTrade.getTradeAmount());
byte[] offererPayoutTxSignature = offererTradeProcessModel.getTradeWalletService().createAndSignPayoutTx(
offererTrade.getDepositTx(), offererTrade.getDepositTx(),
offererPayoutAmount, offererPayoutAmount,
takerPayoutAmount, takerPayoutAmount,

View file

@ -0,0 +1,64 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.util.Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererCreatesAndSignsContract extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsContract.class);
public OffererCreatesAndSignsContract(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
assert offererTradeProcessModel.getTakeOfferFeeTxId() != null;
Contract contract = new Contract(
offererTradeProcessModel.getOffer(),
model.getTradeAmount(),
offererTradeProcessModel.getTakeOfferFeeTxId(),
offererTradeProcessModel.offerer.getAccountId(),
offererTradeProcessModel.offerer.getAccountId(),
offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.getOffer().getP2PSigPubKey(),
offererTradeProcessModel.offerer.getP2pSigPubKey());
String contractAsJson = Utilities.objectToJson(contract);
String signature = offererTradeProcessModel.getSignatureService().signMessage(offererTradeProcessModel.offerer.getRegistrationKeyPair(),
contractAsJson);
model.setContract(contract);
model.setContractAsJson(contractAsJson);
model.setOffererContractSignature(signature);
complete();
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -0,0 +1,65 @@
/*
* 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.btc.FeePolicy;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererCreatesAndSignsDepositTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsDepositTx.class);
public OffererCreatesAndSignsDepositTx(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
assert offererTrade.getTradeAmount() != null;
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE).add(offererTrade.getTradeAmount());
Coin msOutputAmount = offererInputAmount.add(offererTrade.getSecurityDeposit());
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().takerCreatesAndSignsDepositTx(
offererInputAmount,
msOutputAmount,
offererTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.taker.getOutputs(),
offererTradeProcessModel.offerer.getAddressEntry(),
offererTradeProcessModel.taker.getTradeWalletPubKey(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.getArbitratorPubKey());
offererTradeProcessModel.offerer.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
offererTradeProcessModel.offerer.setPreparedDepositTx(result.getDepositTx());
complete();
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -20,6 +20,8 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.TradeWalletService; import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -27,10 +29,10 @@ import org.bitcoinj.core.Coin;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CreateOffererDepositTxInputs extends OffererTradeTask { public class OffererCreatesDepositTxInputs extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateOffererDepositTxInputs.class); private static final Logger log = LoggerFactory.getLogger(OffererCreatesDepositTxInputs.class);
public CreateOffererDepositTxInputs(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererCreatesDepositTxInputs(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -38,8 +40,8 @@ public class CreateOffererDepositTxInputs extends OffererTradeTask {
protected void doRun() { protected void doRun() {
try { try {
log.debug("offererTrade.id" + offererTrade.getId()); log.debug("offererTrade.id" + offererTrade.getId());
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE); Coin inputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(offererInputAmount, TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(inputAmount,
offererTradeProcessModel.offerer.getAddressEntry()); offererTradeProcessModel.offerer.getAddressEntry());
offererTradeProcessModel.offerer.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs()); offererTradeProcessModel.offerer.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
@ -49,7 +51,14 @@ public class CreateOffererDepositTxInputs extends OffererTradeTask {
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
if (offererTrade instanceof OffererAsBuyerTrade) {
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
}
else if (offererTrade instanceof OffererAsSellerTrade) {
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
}
failed(t); failed(t);
} }
} }

View file

@ -0,0 +1,60 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
public class OffererProcessDepositTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessDepositTxPublishedMessage.class);
public OffererProcessDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
DepositTxPublishedMessage message = (DepositTxPublishedMessage) offererTradeProcessModel.getTradeMessage();
checkTradeId(offererTradeProcessModel.getId(), message);
checkNotNull(message);
offererTrade.setDepositTx(checkNotNull(message.depositTx));
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.DEPOSIT_PUBLISHED);
complete();
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -0,0 +1,63 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*;
public class OffererProcessFiatTransferStartedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessFiatTransferStartedMessage.class);
public OffererProcessFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
FiatTransferStartedMessage message = (FiatTransferStartedMessage) offererTradeProcessModel.getTradeMessage();
checkTradeId(offererTradeProcessModel.getId(), message);
checkNotNull(message);
offererTradeProcessModel.taker.setSignature(checkNotNull(message.buyerSignature));
offererTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
offererTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
offererTradeProcessModel.taker.setPayoutAddressString(nonEmptyStringOf(message.buyerPayoutAddress));
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.FIAT_PAYMENT_STARTED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.FIAT_PAYMENT_STARTED);
complete();
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId; import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessPayoutTxPublishedMessage extends OffererTradeTask { public class OffererProcessPayoutTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessPayoutTxPublishedMessage.class); private static final Logger log = LoggerFactory.getLogger(OffererProcessPayoutTxPublishedMessage.class);
public ProcessPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererProcessPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -43,7 +45,10 @@ public class ProcessPayoutTxPublishedMessage extends OffererTradeTask {
offererTrade.setPayoutTx(checkNotNull(message.payoutTx)); offererTrade.setPayoutTx(checkNotNull(message.payoutTx));
offererTrade.setProcessState(OffererTrade.OffererProcessState.PAYOUT_PUBLISHED); if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.PAYOUT_PUBLISHED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.PAYOUT_PUBLISHED);
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
public class ProcessRequestDepositTxInputsMessage extends OffererTradeTask { public class OffererProcessRequestDepositTxInputsMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestDepositTxInputsMessage.class); private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestDepositTxInputsMessage.class);
public ProcessRequestDepositTxInputsMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererProcessRequestDepositTxInputsMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -49,7 +51,12 @@ public class ProcessRequestDepositTxInputsMessage extends OffererTradeTask {
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
failed(t); failed(t);
} }
} }

View file

@ -0,0 +1,60 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class OffererProcessRequestPayDepositMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestPayDepositMessage.class);
public OffererProcessRequestPayDepositMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
RequestPayDepositMessage message = (RequestPayDepositMessage) offererTradeProcessModel.getTradeMessage();
checkTradeId(offererTradeProcessModel.getId(), message);
checkNotNull(message);
offererTradeProcessModel.taker.setConnectedOutputsForAllInputs(checkNotNull(message.buyerConnectedOutputsForAllInputs));
checkArgument(message.buyerConnectedOutputsForAllInputs.size() > 0);
offererTradeProcessModel.taker.setOutputs(checkNotNull(message.buyerOutputs));
offererTradeProcessModel.taker.setTradeWalletPubKey(checkNotNull(message.buyerTradeWalletPubKey));
offererTradeProcessModel.taker.setP2pSigPubKey(checkNotNull(message.buyerP2PSigPublicKey));
offererTradeProcessModel.taker.setP2pEncryptPubKey(checkNotNull(message.buyerP2PEncryptPublicKey));
offererTradeProcessModel.taker.setFiatAccount(checkNotNull(message.buyerFiatAccount));
offererTradeProcessModel.taker.setAccountId(nonEmptyStringOf(message.buyerAccountId));
complete();
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*; import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
public class ProcessRequestPublishDepositTxMessage extends OffererTradeTask { public class OffererProcessRequestPublishDepositTxMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestPublishDepositTxMessage.class); private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestPublishDepositTxMessage.class);
public ProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -43,7 +45,7 @@ public class ProcessRequestPublishDepositTxMessage extends OffererTradeTask {
offererTradeProcessModel.taker.setFiatAccount(checkNotNull(message.takerFiatAccount)); offererTradeProcessModel.taker.setFiatAccount(checkNotNull(message.takerFiatAccount));
offererTradeProcessModel.taker.setAccountId(nonEmptyStringOf(message.takerAccountId)); offererTradeProcessModel.taker.setAccountId(nonEmptyStringOf(message.takerAccountId));
offererTradeProcessModel.taker.setP2pSigPublicKey(checkNotNull(message.takerP2PSigPublicKey)); offererTradeProcessModel.taker.setP2pSigPubKey(checkNotNull(message.takerP2PSigPublicKey));
offererTradeProcessModel.taker.setP2pEncryptPubKey(checkNotNull(message.takerP2PEncryptPublicKey)); offererTradeProcessModel.taker.setP2pEncryptPubKey(checkNotNull(message.takerP2PEncryptPublicKey));
offererTradeProcessModel.taker.setContractAsJson(nonEmptyStringOf(message.takerContractAsJson)); offererTradeProcessModel.taker.setContractAsJson(nonEmptyStringOf(message.takerContractAsJson));
offererTradeProcessModel.taker.setContractSignature(nonEmptyStringOf(message.takerContractSignature)); offererTradeProcessModel.taker.setContractSignature(nonEmptyStringOf(message.takerContractSignature));
@ -56,7 +58,12 @@ public class ProcessRequestPublishDepositTxMessage extends OffererTradeTask {
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
failed(t); failed(t);
} }
} }

View file

@ -19,16 +19,18 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendDepositTxPublishedMessage extends OffererTradeTask { public class OffererSendsDepositTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendDepositTxPublishedMessage.class); private static final Logger log = LoggerFactory.getLogger(OffererSendsDepositTxPublishedMessage.class);
public SendDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererSendsDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -48,7 +50,12 @@ public class SendDepositTxPublishedMessage extends OffererTradeTask {
public void handleFault() { public void handleFault() {
appendToErrorMessage("Sending DepositTxPublishedMessage failed"); appendToErrorMessage("Sending DepositTxPublishedMessage failed");
offererTrade.setErrorMessage(errorMessage); offererTrade.setErrorMessage(errorMessage);
offererTrade.setProcessState(OffererTrade.OffererProcessState.MESSAGE_SENDING_FAILED);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed(); failed();
} }
}); });

View file

@ -19,16 +19,18 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendFiatTransferStartedMessage extends OffererTradeTask { public class OffererSendsFiatTransferStartedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendFiatTransferStartedMessage.class); private static final Logger log = LoggerFactory.getLogger(OffererSendsFiatTransferStartedMessage.class);
public SendFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererSendsFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -42,13 +44,20 @@ public class SendFiatTransferStartedMessage extends OffererTradeTask {
offererTradeProcessModel.offerer.getAddressEntry().getAddressString()); offererTradeProcessModel.offerer.getAddressEntry().getAddressString());
offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage, offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage,
offererTradeProcessModel.taker.getP2pSigPublicKey(), offererTradeProcessModel.taker.getP2pSigPubKey(),
offererTradeProcessModel.taker.getP2pEncryptPubKey(), offererTradeProcessModel.taker.getP2pEncryptPubKey(),
new SendMessageListener() { new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("Sending FiatTransferStartedMessage succeeded."); log.trace("Sending FiatTransferStartedMessage succeeded.");
offererTrade.setProcessState(OffererTrade.OffererProcessState.FIAT_PAYMENT_STARTED);
if (offererTrade instanceof OffererAsBuyerTrade) {
((OffererAsBuyerTrade) offererTrade).setProcessState(OffererAsBuyerTrade.ProcessState.FIAT_PAYMENT_STARTED);
}
else if (offererTrade instanceof OffererAsSellerTrade) {
((OffererAsSellerTrade) offererTrade).setProcessState(OffererAsSellerTrade.ProcessState.FIAT_PAYMENT_STARTED);
}
complete(); complete();
} }
@ -56,7 +65,14 @@ public class SendFiatTransferStartedMessage extends OffererTradeTask {
public void handleFault() { public void handleFault() {
appendToErrorMessage("Sending FiatTransferStartedMessage failed"); appendToErrorMessage("Sending FiatTransferStartedMessage failed");
offererTrade.setErrorMessage(errorMessage); offererTrade.setErrorMessage(errorMessage);
offererTrade.setProcessState(OffererTrade.OffererProcessState.MESSAGE_SENDING_FAILED);
if (offererTrade instanceof OffererAsBuyerTrade) {
((OffererAsBuyerTrade) offererTrade).setProcessState(OffererAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
}
else if (offererTrade instanceof OffererAsSellerTrade) {
((OffererAsSellerTrade) offererTrade).setProcessState(OffererAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
}
failed(); failed();
} }
}); });

View file

@ -0,0 +1,71 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererSendsPayoutTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsPayoutTxPublishedMessage.class);
public OffererSendsPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(offererTradeProcessModel.getId(), offererTradeProcessModel.getPayoutTx());
offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(),
tradeMessage,
offererTradeProcessModel.offerer.getP2pSigPublicKey(),
offererTradeProcessModel.offerer.getP2pEncryptPubKey(),
new SendMessageListener() {
@Override
public void handleResult() {
log.trace("PayoutTxPublishedMessage successfully arrived at peer");
complete();
}
@Override
public void handleFault() {
appendToErrorMessage("Sending PayoutTxPublishedMessage failed");
offererTrade.setErrorMessage(errorMessage);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -19,52 +19,59 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendRequestTakerDepositPaymentMessage extends OffererTradeTask { public class OffererSendsRequestPublishDepositTxMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendRequestTakerDepositPaymentMessage.class); private static final Logger log = LoggerFactory.getLogger(OffererSendsRequestPublishDepositTxMessage.class);
public SendRequestTakerDepositPaymentMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererSendsRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, model);
} }
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage( RequestPublishDepositTxMessage tradeMessage = new RequestPublishDepositTxMessage(
offererTradeProcessModel.getId(), offererTradeProcessModel.getId(),
offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.offerer.getOutputs(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.offerer.getP2pEncryptPubKey(),
offererTradeProcessModel.offerer.getFiatAccount(), offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.offerer.getAccountId()); offererTradeProcessModel.offerer.getAccountId(),
offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.offerer.getP2pEncryptPublicKey(),
offererTrade.getContractAsJson(),
offererTrade.getOffererContractSignature(),
offererTradeProcessModel.offerer.getAddressEntry().getAddressString(),
offererTradeProcessModel.offerer.getPreparedDepositTx(),
offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs()
);
offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage, new SendMessageListener() { offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
complete(); complete();
} }
@Override @Override
public void handleFault() { public void handleFault() {
appendToErrorMessage("Sending RequestTakerDepositPaymentMessage failed"); appendToErrorMessage("Sending RequestOffererPublishDepositTxMessage failed");
offererTrade.setErrorMessage(errorMessage); offererTrade.setErrorMessage(errorMessage);
offererTrade.setProcessState(OffererTrade.OffererProcessState.MESSAGE_SENDING_FAILED);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN); if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed(); failed();
} }
}); });
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
failed(t); failed(t);
} }
} }

View file

@ -0,0 +1,89 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererSendsRequestSellerDepositPaymentMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsRequestSellerDepositPaymentMessage.class);
public OffererSendsRequestSellerDepositPaymentMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@Override
protected void doRun() {
try {
RequestPayDepositMessage tradeMessage = new RequestPayDepositMessage(
offererTradeProcessModel.getId(),
offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.offerer.getOutputs(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.offerer.getP2pEncryptPubKey(),
offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.offerer.getAccountId());
offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
complete();
}
@Override
public void handleFault() {
appendToErrorMessage("Sending RequestTakerDepositPaymentMessage failed");
offererTrade.setErrorMessage(errorMessage);
if (offererTrade instanceof OffererAsBuyerTrade) {
((OffererAsBuyerTrade) offererTrade).setProcessState(OffererAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
((OffererAsBuyerTrade) offererTrade).setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
}
else if (offererTrade instanceof OffererAsSellerTrade) {
((OffererAsSellerTrade) offererTrade).setProcessState(OffererAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
((OffererAsSellerTrade) offererTrade).setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
}
failed();
}
});
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
if (offererTrade instanceof OffererAsBuyerTrade) {
((OffererAsBuyerTrade) offererTrade).setProcessState(OffererAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
((OffererAsSellerTrade) offererTrade).setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
}
else if (offererTrade instanceof OffererAsSellerTrade) {
((OffererAsSellerTrade) offererTrade).setProcessState(OffererAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
((OffererAsSellerTrade) offererTrade).setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
}
failed(t);
}
}
}

View file

@ -0,0 +1,101 @@
/*
* 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.btc.FeePolicy;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererSignsAndPublishDepositTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSignsAndPublishDepositTx.class);
public OffererSignsAndPublishDepositTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@Override
protected void doRun() {
try {
Coin inputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
offererTradeProcessModel.getTradeWalletService().signAndPublishDepositTx(
offererTradeProcessModel.taker.getPreparedDepositTx(),
offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.offerer.getOutputs(),
inputAmount,
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.taker.getTradeWalletPubKey(),
offererTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("offererSignAndPublishTx succeeded " + transaction);
offererTrade.setDepositTx(transaction);
if (offererTrade instanceof OffererAsBuyerTrade) {
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED);
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.PENDING);
}
else if (offererTrade instanceof OffererAsSellerTrade) {
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.DEPOSIT_PUBLISHED);
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.PENDING);
}
complete();
}
@Override
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
failed(t);
}
});
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
failed(t);
}
}
}

View file

@ -17,11 +17,11 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
@ -31,34 +31,35 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SignAndPublishDepositTx extends OffererTradeTask { public class OffererSignsAndPublishPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class); private static final Logger log = LoggerFactory.getLogger(OffererSignsAndPublishPayoutTx.class);
public SignAndPublishDepositTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererSignsAndPublishPayoutTx(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, model);
} }
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE); offererTradeProcessModel.getTradeWalletService().signAndPublishPayoutTx(
offererTradeProcessModel.getTradeWalletService().offererSignsAndPublishDepositTx( offererTrade.getDepositTx(),
offererTradeProcessModel.taker.getPreparedDepositTx(), offererTradeProcessModel.taker.getSignature(),
offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(), offererTradeProcessModel.offerer.getPayoutAmount(),
offererTradeProcessModel.taker.getConnectedOutputsForAllInputs(), offererTradeProcessModel.taker.getPayoutAmount(),
offererTradeProcessModel.offerer.getOutputs(), offererTradeProcessModel.taker.getPayoutAddressString(),
offererInputAmount, offererTradeProcessModel.offerer.getAddressEntry(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(), offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.taker.getTradeWalletPubKey(), offererTradeProcessModel.taker.getTradeWalletPubKey(),
offererTradeProcessModel.getArbitratorPubKey(), offererTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() { new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {
log.trace("offererSignAndPublishTx succeeded " + transaction); offererTradeProcessModel.setPayoutTx(transaction);
offererTrade.setDepositTx(transaction); if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererTrade.OffererProcessState.DEPOSIT_PUBLISHED); offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.PAYOUT_PUBLISHED);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.PENDING); else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.PAYOUT_PUBLISHED);
complete(); complete();
} }
@ -67,14 +68,12 @@ public class SignAndPublishDepositTx extends OffererTradeTask {
public void onFailure(@NotNull Throwable t) { public void onFailure(@NotNull Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
failed(t); failed(t);
} }
}); });
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
failed(t); failed(t);
} }
} }

View file

@ -19,16 +19,18 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Contract; import io.bitsquare.trade.Contract;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class VerifyAndSignContract extends OffererTradeTask { public class OffererVerifiesAndSignsContract extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class); private static final Logger log = LoggerFactory.getLogger(OffererVerifiesAndSignsContract.class);
public VerifyAndSignContract(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) { public OffererVerifiesAndSignsContract(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel); super(taskHandler, offererTradeProcessModel);
} }
@ -44,7 +46,7 @@ public class VerifyAndSignContract extends OffererTradeTask {
offererTradeProcessModel.offerer.getFiatAccount(), offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.taker.getFiatAccount(), offererTradeProcessModel.taker.getFiatAccount(),
offererTradeProcessModel.offerer.getP2pSigPubKey(), offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.taker.getP2pSigPublicKey()); offererTradeProcessModel.taker.getP2pSigPubKey());
String contractAsJson = Utilities.objectToJson(contract); String contractAsJson = Utilities.objectToJson(contract);
String signature = offererTradeProcessModel.getSignatureService().signMessage(offererTradeProcessModel.offerer.getRegistrationKeyPair(), String signature = offererTradeProcessModel.getSignatureService().signMessage(offererTradeProcessModel.offerer.getRegistrationKeyPair(),
contractAsJson); contractAsJson);
@ -58,7 +60,12 @@ public class VerifyAndSignContract extends OffererTradeTask {
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
failed(t); failed(t);
} }
} }

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -47,12 +49,21 @@ public class VerifyTakerAccount extends OffererTradeTask {
} }
else { else {
failed("Account registration validation for peer failed."); failed("Account registration validation for peer failed.");
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
} }
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
offererTrade.setThrowable(t); offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_OPEN);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_OPEN);
failed(t); failed(t);
} }
} }

View file

@ -0,0 +1,201 @@
/*
* 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.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.MessageHandler;
import io.bitsquare.p2p.Peer;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.protocol.Protocol;
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel;
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitsPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesDepositTxInputs;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestPayDepositMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSignsAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerVerifiesAndSignsContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class TakerAsBuyerProtocol implements Protocol {
private static final Logger log = LoggerFactory.getLogger(TakerAsBuyerProtocol.class);
private final TakerAsBuyerTrade takerAsBuyerTrade;
private final TakerProcessModel takerTradeProcessModel;
private final MessageHandler messageHandler;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public TakerAsBuyerProtocol(TakerAsBuyerTrade takerTrade) {
log.debug("New SellerAsTakerProtocol " + this);
this.takerAsBuyerTrade = takerTrade;
takerTradeProcessModel = takerTrade.getProcessModel();
messageHandler = this::handleMessage;
takerTradeProcessModel.getMessageService().addMessageHandler(messageHandler);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
public void cleanup() {
log.debug("cleanup " + this);
takerTradeProcessModel.getMessageService().removeMessageHandler(messageHandler);
}
public void setMailboxMessage(MailboxMessage mailboxMessage) {
log.debug("setMailboxMessage " + mailboxMessage);
// Might be called twice, so check that its only processed once
/* if (takerTradeProcessModel.getMailboxMessage() == null) {
takerTradeProcessModel.setMailboxMessage(mailboxMessage);
if (mailboxMessage instanceof FiatTransferStartedMessage) {
handleFiatTransferStartedMessage((FiatTransferStartedMessage) mailboxMessage);
}
else if (mailboxMessage instanceof DepositTxPublishedMessage) {
handleDepositTxPublishedMessage((DepositTxPublishedMessage) mailboxMessage);
}
}*/
}
public void takeAvailableOffer() {
TaskRunner<TakerAsBuyerTrade> taskRunner = new TaskRunner<>(takerAsBuyerTrade,
() -> log.debug("taskRunner at takeAvailableOffer completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
CreateTakeOfferFeeTx.class,
BroadcastTakeOfferFeeTx.class,
TakerCreatesDepositTxInputs.class,
TakerSendsRequestPayDepositMessage.class
);
taskRunner.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
private void handle(RequestPublishDepositTxMessage tradeMessage) {
takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerAsBuyerTrade> taskRunner = new TaskRunner<>(takerAsBuyerTrade,
() -> log.debug("taskRunner at handleRequestPublishDepositTxMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
TakerProcessRequestPublishDepositTxMessage.class,
VerifyOffererAccount.class,
TakerVerifiesAndSignsContract.class,
TakerSignsAndPublishDepositTx.class,
TakerSendsDepositTxPublishedMessage.class
);
taskRunner.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Called from UI
///////////////////////////////////////////////////////////////////////////////////////////
// User clicked the "bank transfer started" button
public void onFiatPaymentStarted() {
TaskRunner<TakerAsBuyerTrade> taskRunner = new TaskRunner<>(takerAsBuyerTrade,
() -> log.debug("taskRunner at onFiatPaymentStarted completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
VerifyOfferFeePayment.class,
TakerCreatesAndSignsPayoutTx.class,
TakerSendsFiatTransferStartedMessage.class
);
taskRunner.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message handling
///////////////////////////////////////////////////////////////////////////////////////////
private void handle(PayoutTxPublishedMessage tradeMessage) {
takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerAsBuyerTrade> taskRunner = new TaskRunner<>(takerAsBuyerTrade,
() -> {
log.debug("taskRunner at handlePayoutTxPublishedMessage completed");
// we are done!
takerTradeProcessModel.onComplete();
},
this::handleTaskRunnerFault);
taskRunner.addTasks(
TakerProcessPayoutTxPublishedMessage.class,
TakerCommitsPayoutTx.class);
taskRunner.run();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Massage dispatcher
///////////////////////////////////////////////////////////////////////////////////////////
private void handleMessage(Message message, Peer sender) {
log.trace("handleNewMessage: message = " + message.getClass().getSimpleName() + " from " + sender);
if (message instanceof TradeMessage) {
TradeMessage tradeMessage = (TradeMessage) message;
nonEmptyStringOf(tradeMessage.tradeId);
if (tradeMessage.tradeId.equals(takerTradeProcessModel.getId())) {
if (tradeMessage instanceof RequestPublishDepositTxMessage) {
handle((RequestPublishDepositTxMessage) tradeMessage);
}
else if (tradeMessage instanceof PayoutTxPublishedMessage) {
handle((PayoutTxPublishedMessage) tradeMessage);
}
else {
log.error("Incoming message not supported. " + tradeMessage);
}
}
}
}
private void handleTaskRunnerFault(String errorMessage) {
log.error(errorMessage);
cleanup();
}
}

View file

@ -22,25 +22,26 @@ import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.Message; import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.MessageHandler; import io.bitsquare.p2p.MessageHandler;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.Protocol; import io.bitsquare.trade.protocol.Protocol;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage; import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel; import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel;
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx; 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.TakerCommitDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessFiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessRequestSellerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx; import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSignsAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CommitDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment; import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount; import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount;
@ -49,10 +50,10 @@ import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.nonEmptyStringOf; import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class TakerProtocol implements Protocol { public class TakerAsSellerProtocol implements Protocol {
private static final Logger log = LoggerFactory.getLogger(TakerProtocol.class); private static final Logger log = LoggerFactory.getLogger(TakerAsSellerProtocol.class);
private final TakerTrade takerTrade; private final TakerAsSellerTrade takerAsSellerTrade;
private final TakerProcessModel takerTradeProcessModel; private final TakerProcessModel takerTradeProcessModel;
private final MessageHandler messageHandler; private final MessageHandler messageHandler;
@ -61,9 +62,9 @@ public class TakerProtocol implements Protocol {
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public TakerProtocol(TakerTrade takerTrade) { public TakerAsSellerProtocol(TakerAsSellerTrade takerTrade) {
log.debug("New SellerAsTakerProtocol " + this); log.debug("New SellerAsTakerProtocol " + this);
this.takerTrade = takerTrade; this.takerAsSellerTrade = takerTrade;
takerTradeProcessModel = takerTrade.getProcessModel(); takerTradeProcessModel = takerTrade.getProcessModel();
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
@ -95,14 +96,14 @@ public class TakerProtocol implements Protocol {
} }
public void takeAvailableOffer() { public void takeAvailableOffer() {
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerAsSellerTrade,
() -> log.debug("taskRunner at takeAvailableOffer completed"), () -> log.debug("taskRunner at takeAvailableOffer completed"),
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
CreateTakeOfferFeeTx.class, CreateTakeOfferFeeTx.class,
BroadcastTakeOfferFeeTx.class, BroadcastTakeOfferFeeTx.class,
SendRequestDepositTxInputsMessage.class TakerSendsRequestDepositTxInputsMessage.class
); );
taskRunner.run(); taskRunner.run();
} }
@ -112,19 +113,19 @@ public class TakerProtocol implements Protocol {
// Incoming message handling // Incoming message handling
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void handleRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage tradeMessage) { private void handleRequestTakerDepositPaymentMessage(RequestPayDepositMessage tradeMessage) {
takerTradeProcessModel.setTradeMessage(tradeMessage); takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerAsSellerTrade,
() -> log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"), () -> log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"),
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
ProcessRequestTakerDepositPaymentMessage.class, TakerProcessRequestSellerDepositPaymentMessage.class,
VerifyOffererAccount.class, VerifyOffererAccount.class,
CreateAndSignContract.class, TakerCreatesAndSignContract.class,
CreateAndSignDepositTx.class, TakerCreatesAndSignsDepositTx.class,
SendRequestPublishDepositTxMessage.class TakerSendsRequestPublishDepositTxMessage.class
); );
taskRunner.run(); taskRunner.run();
} }
@ -132,13 +133,13 @@ public class TakerProtocol implements Protocol {
private void handleDepositTxPublishedMessage(DepositTxPublishedMessage tradeMessage) { private void handleDepositTxPublishedMessage(DepositTxPublishedMessage tradeMessage) {
takerTradeProcessModel.setTradeMessage(tradeMessage); takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerAsSellerTrade> taskRunner = new TaskRunner<>(takerAsSellerTrade,
() -> log.debug("taskRunner at handleDepositTxPublishedMessage completed"), () -> log.debug("taskRunner at handleDepositTxPublishedMessage completed"),
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
ProcessDepositTxPublishedMessage.class, TakerProcessDepositTxPublishedMessage.class,
CommitDepositTx.class TakerCommitDepositTx.class
); );
taskRunner.run(); taskRunner.run();
} }
@ -146,11 +147,11 @@ public class TakerProtocol implements Protocol {
private void handleFiatTransferStartedMessage(FiatTransferStartedMessage tradeMessage) { private void handleFiatTransferStartedMessage(FiatTransferStartedMessage tradeMessage) {
takerTradeProcessModel.setTradeMessage(tradeMessage); takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerAsSellerTrade> taskRunner = new TaskRunner<>(takerAsSellerTrade,
() -> log.debug("taskRunner at handleFiatTransferStartedMessage completed"), () -> log.debug("taskRunner at handleFiatTransferStartedMessage completed"),
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks(ProcessFiatTransferStartedMessage.class); taskRunner.addTasks(TakerProcessFiatTransferStartedMessage.class);
taskRunner.run(); taskRunner.run();
} }
@ -161,9 +162,9 @@ public class TakerProtocol implements Protocol {
// User clicked the "bank transfer received" button, so we release the funds for pay out // User clicked the "bank transfer received" button, so we release the funds for pay out
public void onFiatPaymentReceived() { public void onFiatPaymentReceived() {
takerTrade.setProcessState(TakerTrade.TakerProcessState.FIAT_PAYMENT_RECEIVED); takerAsSellerTrade.setProcessState(TakerAsSellerTrade.ProcessState.FIAT_PAYMENT_RECEIVED);
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerAsSellerTrade> taskRunner = new TaskRunner<>(takerAsSellerTrade,
() -> { () -> {
log.debug("taskRunner at handleFiatReceivedUIEvent completed"); log.debug("taskRunner at handleFiatReceivedUIEvent completed");
@ -173,9 +174,9 @@ public class TakerProtocol implements Protocol {
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
SignAndPublishPayoutTx.class,
VerifyOfferFeePayment.class, VerifyOfferFeePayment.class,
SendPayoutTxPublishedMessage.class TakerSignsAndPublishPayoutTx.class,
TakerSendsPayoutTxPublishedMessage.class
); );
taskRunner.run(); taskRunner.run();
} }
@ -191,8 +192,8 @@ public class TakerProtocol implements Protocol {
nonEmptyStringOf(tradeMessage.tradeId); nonEmptyStringOf(tradeMessage.tradeId);
if (tradeMessage.tradeId.equals(takerTradeProcessModel.getId())) { if (tradeMessage.tradeId.equals(takerTradeProcessModel.getId())) {
if (tradeMessage instanceof RequestTakerDepositPaymentMessage) { if (tradeMessage instanceof RequestPayDepositMessage) {
handleRequestTakerDepositPaymentMessage((RequestTakerDepositPaymentMessage) tradeMessage); handleRequestTakerDepositPaymentMessage((RequestPayDepositMessage) tradeMessage);
} }
else if (tradeMessage instanceof DepositTxPublishedMessage) { else if (tradeMessage instanceof DepositTxPublishedMessage) {
handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage); handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);

View file

@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.models;
import io.bitsquare.fiat.FiatAccount; import io.bitsquare.fiat.FiatAccount;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import java.io.IOException; import java.io.IOException;
@ -56,6 +57,10 @@ public class Offerer implements Serializable {
private String accountId; private String accountId;
private PublicKey p2pSigPublicKey; private PublicKey p2pSigPublicKey;
private PublicKey p2pEncryptPubKey; private PublicKey p2pEncryptPubKey;
private String contractAsJson;
private String contractSignature;
private Transaction preparedDepositTx;
private PublicKey p2pSigPubKey;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -166,6 +171,41 @@ public class Offerer implements Serializable {
this.p2pEncryptPubKey = p2pEncryptPubKey; this.p2pEncryptPubKey = p2pEncryptPubKey;
} }
@Nullable
public String getContractAsJson() {
return contractAsJson;
}
public void setContractAsJson(String contractAsJson) {
this.contractAsJson = contractAsJson;
}
@Nullable
public String getContractSignature() {
return contractSignature;
}
public void setContractSignature(String contractSignature) {
this.contractSignature = contractSignature;
}
@Nullable
public Transaction getPreparedDepositTx() {
return preparedDepositTx;
}
public void setPreparedDepositTx(Transaction preparedDepositTx) {
this.preparedDepositTx = preparedDepositTx;
}
@Nullable
public PublicKey getP2pSigPubKey() {
return p2pSigPubKey;
}
public void setP2pSigPubKey(PublicKey p2pSigPubKey) {
this.p2pSigPubKey = p2pSigPubKey;
}
@Override @Override
public String toString() { public String toString() {

View file

@ -56,7 +56,8 @@ public class Taker implements Serializable {
private List<TransactionOutput> connectedOutputsForAllInputs; private List<TransactionOutput> connectedOutputsForAllInputs;
private Coin payoutAmount; private Coin payoutAmount;
private Transaction preparedDepositTx; private Transaction preparedDepositTx;
private List<TransactionOutput> outputs; // used to verify amounts with change outputs
private byte[] payoutTxSignature;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
@ -118,6 +119,10 @@ public class Taker implements Serializable {
return getAddressEntry().getPubKey(); return getAddressEntry().getPubKey();
} }
public PublicKey getP2pEncryptPubKey() {
return user.getP2PEncryptPubKey();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects // Getter/Setter for Mutable objects
@ -150,6 +155,24 @@ public class Taker implements Serializable {
this.preparedDepositTx = preparedDepositTx; this.preparedDepositTx = preparedDepositTx;
} }
@Nullable
public List<TransactionOutput> getOutputs() {
return outputs;
}
public void setOutputs(List<TransactionOutput> outputs) {
this.outputs = outputs;
}
@Nullable
public byte[] getPayoutTxSignature() {
return payoutTxSignature;
}
public void setPayoutTxSignature(byte[] payoutTxSignature) {
this.payoutTxSignature = payoutTxSignature;
}
@Override @Override
public String toString() { public String toString() {
return "Taker{" + return "Taker{" +
@ -161,4 +184,6 @@ public class Taker implements Serializable {
", preparedDepositTx=" + preparedDepositTx + ", preparedDepositTx=" + preparedDepositTx +
'}'; '}';
} }
} }

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.taker.tasks; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -45,8 +47,10 @@ public class BroadcastTakeOfferFeeTx extends TakerTradeTask {
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {
log.debug("Take offer fee published successfully. Transaction ID = " + transaction.getHashAsString()); log.debug("Take offer fee published successfully. Transaction ID = " + transaction.getHashAsString());
takerTrade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_PUBLISHED); if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.TAKE_OFFER_FEE_PUBLISHED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.TAKE_OFFER_FEE_PUBLISHED);
complete(); complete();
} }
@ -55,7 +59,11 @@ public class BroadcastTakeOfferFeeTx extends TakerTradeTask {
t.printStackTrace(); t.printStackTrace();
appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again."); appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again.");
takerTrade.setErrorMessage(errorMessage); takerTrade.setErrorMessage(errorMessage);
takerTrade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_PUBLISH_FAILED);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.TAKE_OFFER_FEE_PUBLISH_FAILED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.TAKE_OFFER_FEE_PUBLISH_FAILED);
failed(t); failed(t);
} }

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.taker.tasks; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -39,7 +41,11 @@ public class CreateTakeOfferFeeTx extends TakerTradeTask {
.getAddressEntry()); .getAddressEntry());
takerTradeProcessModel.setTakeOfferFeeTx(createTakeOfferFeeTx); takerTradeProcessModel.setTakeOfferFeeTx(createTakeOfferFeeTx);
takerTrade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_TX_CREATED);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.TAKE_OFFER_FEE_TX_CREATED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.TAKE_OFFER_FEE_TX_CREATED);
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -25,10 +25,10 @@ import org.bitcoinj.core.Transaction;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CommitDepositTx extends TakerTradeTask { public class TakerCommitDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(CommitDepositTx.class); private static final Logger log = LoggerFactory.getLogger(TakerCommitDepositTx.class);
public CommitDepositTx(TaskRunner taskHandler, TakerTrade model) { public TakerCommitDepositTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }

View file

@ -0,0 +1,49 @@
/*
* 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.TaskRunner;
import io.bitsquare.trade.TakerTrade;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerCommitsPayoutTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCommitsPayoutTx.class);
public TakerCommitsPayoutTx(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
Transaction transaction = takerTradeProcessModel.getTradeWalletService().commitTx(takerTrade.getPayoutTx());
takerTrade.setPayoutTx(transaction);
complete();
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -25,10 +25,10 @@ import io.bitsquare.util.Utilities;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CreateAndSignContract extends TakerTradeTask { public class TakerCreatesAndSignContract extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class); private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignContract.class);
public CreateAndSignContract(TaskRunner taskHandler, TakerTrade model) { public TakerCreatesAndSignContract(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }

View file

@ -27,10 +27,10 @@ import org.bitcoinj.core.Coin;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CreateAndSignDepositTx extends TakerTradeTask { public class TakerCreatesAndSignsDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignDepositTx.class); private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignsDepositTx.class);
public CreateAndSignDepositTx(TaskRunner taskHandler, TakerTrade model) { public TakerCreatesAndSignsDepositTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }
@ -38,7 +38,7 @@ public class CreateAndSignDepositTx extends TakerTradeTask {
protected void doRun() { protected void doRun() {
try { try {
assert takerTrade.getTradeAmount() != null; assert takerTrade.getTradeAmount() != null;
Coin takerInputAmount = takerTrade.getTradeAmount().add(takerTrade.getSecurityDeposit()).add(FeePolicy.TX_FEE); Coin takerInputAmount = takerTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
Coin msOutputAmount = takerInputAmount.add(takerTrade.getSecurityDeposit()); Coin msOutputAmount = takerInputAmount.add(takerTrade.getSecurityDeposit());
TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().takerCreatesAndSignsDepositTx( TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().takerCreatesAndSignsDepositTx(

View file

@ -0,0 +1,66 @@
/*
* 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.TaskRunner;
import io.bitsquare.trade.TakerTrade;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerCreatesAndSignsPayoutTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignsPayoutTx.class);
public TakerCreatesAndSignsPayoutTx(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
assert takerTrade.getTradeAmount() != null;
Coin securityDeposit = takerTrade.getSecurityDeposit();
Coin offererPayoutAmount = securityDeposit;
Coin takerPayoutAmount = securityDeposit.add(takerTrade.getTradeAmount());
byte[] takerPayoutTxSignature = takerTradeProcessModel.getTradeWalletService().createAndSignPayoutTx(
takerTrade.getDepositTx(),
offererPayoutAmount,
takerPayoutAmount,
takerTradeProcessModel.taker.getAddressEntry(),
takerTradeProcessModel.offerer.getPayoutAddressString(),
takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.getArbitratorPubKey());
takerTradeProcessModel.taker.setPayoutTxSignature(takerPayoutTxSignature);
takerTradeProcessModel.taker.setPayoutAmount(takerPayoutAmount);
takerTradeProcessModel.offerer.setPayoutAmount(offererPayoutAmount);
complete();
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -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.taker.tasks;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerTrade;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerCreatesDepositTxInputs extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesDepositTxInputs.class);
public TakerCreatesDepositTxInputs(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
log.debug("takerTrade.id" + takerTrade.getId());
Coin inputAmount = takerTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(inputAmount,
takerTradeProcessModel.taker.getAddressEntry());
takerTradeProcessModel.taker.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
takerTradeProcessModel.taker.setOutputs(result.getOutputs());
complete();
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.taker.tasks; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId; import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessDepositTxPublishedMessage extends TakerTradeTask { public class TakerProcessDepositTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessDepositTxPublishedMessage.class); private static final Logger log = LoggerFactory.getLogger(TakerProcessDepositTxPublishedMessage.class);
public ProcessDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) { public TakerProcessDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }
@ -42,7 +44,11 @@ public class ProcessDepositTxPublishedMessage extends TakerTradeTask {
checkNotNull(message); checkNotNull(message);
takerTrade.setDepositTx(checkNotNull(message.depositTx)); takerTrade.setDepositTx(checkNotNull(message.depositTx));
takerTrade.setProcessState(TakerTrade.TakerProcessState.DEPOSIT_PUBLISHED);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.DEPOSIT_PUBLISHED);
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -18,6 +18,8 @@
package io.bitsquare.trade.protocol.trade.taker.tasks; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
public class ProcessFiatTransferStartedMessage extends TakerTradeTask { public class TakerProcessFiatTransferStartedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessFiatTransferStartedMessage.class); private static final Logger log = LoggerFactory.getLogger(TakerProcessFiatTransferStartedMessage.class);
public ProcessFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade model) { public TakerProcessFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }
@ -41,11 +43,15 @@ public class ProcessFiatTransferStartedMessage extends TakerTradeTask {
checkTradeId(takerTradeProcessModel.getId(), message); checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message); checkNotNull(message);
takerTradeProcessModel.offerer.setSignature(checkNotNull(message.offererSignature)); takerTradeProcessModel.offerer.setSignature(checkNotNull(message.buyerSignature));
takerTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount))); takerTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
takerTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount))); takerTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount)));
takerTradeProcessModel.offerer.setPayoutAddressString(nonEmptyStringOf(message.offererPayoutAddress)); takerTradeProcessModel.offerer.setPayoutAddressString(nonEmptyStringOf(message.buyerPayoutAddress));
takerTrade.setProcessState(TakerTrade.TakerProcessState.FIAT_PAYMENT_STARTED);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.FIAT_PAYMENT_STARTED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.FIAT_PAYMENT_STARTED);
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -0,0 +1,60 @@
/*
* 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.TaskRunner;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
public class TakerProcessPayoutTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessPayoutTxPublishedMessage.class);
public TakerProcessPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
PayoutTxPublishedMessage message = (PayoutTxPublishedMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTrade.setPayoutTx(checkNotNull(message.payoutTx));
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.PAYOUT_PUBLISHED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.PAYOUT_PUBLISHED);
complete();
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -0,0 +1,63 @@
/*
* 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.TaskRunner;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class TakerProcessRequestPublishDepositTxMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessRequestPublishDepositTxMessage.class);
public TakerProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
RequestPublishDepositTxMessage message = (RequestPublishDepositTxMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.takerFiatAccount));
takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.takerAccountId));
takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.takerP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.takerP2PEncryptPublicKey));
takerTradeProcessModel.offerer.setContractAsJson(nonEmptyStringOf(message.takerContractAsJson));
takerTradeProcessModel.offerer.setContractSignature(nonEmptyStringOf(message.takerContractSignature));
takerTradeProcessModel.offerer.setPayoutAddressString(nonEmptyStringOf(message.takerPayoutAddressString));
takerTradeProcessModel.offerer.setPreparedDepositTx(checkNotNull(message.takersPreparedDepositTx));
takerTradeProcessModel.offerer.setConnectedOutputsForAllInputs(checkNotNull(message.takerConnectedOutputsForAllInputs));
checkArgument(message.takerConnectedOutputsForAllInputs.size() > 0);
complete();
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -27,28 +27,28 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*; import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
public class ProcessRequestTakerDepositPaymentMessage extends TakerTradeTask { public class TakerProcessRequestSellerDepositPaymentMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestTakerDepositPaymentMessage.class); private static final Logger log = LoggerFactory.getLogger(TakerProcessRequestSellerDepositPaymentMessage.class);
public ProcessRequestTakerDepositPaymentMessage(TaskRunner taskHandler, TakerTrade model) { public TakerProcessRequestSellerDepositPaymentMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
RequestTakerDepositPaymentMessage message = (RequestTakerDepositPaymentMessage) takerTradeProcessModel.getTradeMessage(); RequestPayDepositMessage message = (RequestPayDepositMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message); checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message); checkNotNull(message);
takerTradeProcessModel.offerer.setConnectedOutputsForAllInputs(checkNotNull(message.offererConnectedOutputsForAllInputs)); takerTradeProcessModel.offerer.setConnectedOutputsForAllInputs(checkNotNull(message.buyerConnectedOutputsForAllInputs));
checkArgument(message.offererConnectedOutputsForAllInputs.size() > 0); checkArgument(message.buyerConnectedOutputsForAllInputs.size() > 0);
takerTradeProcessModel.offerer.setOutputs(checkNotNull(message.offererOutputs)); takerTradeProcessModel.offerer.setOutputs(checkNotNull(message.buyerOutputs));
takerTradeProcessModel.offerer.setTradeWalletPubKey(checkNotNull(message.offererTradeWalletPubKey)); takerTradeProcessModel.offerer.setTradeWalletPubKey(checkNotNull(message.buyerTradeWalletPubKey));
takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.offererP2PSigPublicKey)); takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.buyerP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.offererP2PEncryptPublicKey)); takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.buyerP2PEncryptPublicKey));
takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.offererFiatAccount)); takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.buyerFiatAccount));
takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.offererAccountId)); takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.buyerAccountId));
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -0,0 +1,68 @@
/*
* 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.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerSendsDepositTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsDepositTxPublishedMessage.class);
public TakerSendsDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(takerTradeProcessModel.getId(), takerTrade.getDepositTx());
takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("DepositTxPublishedMessage successfully arrived at peer");
complete();
}
@Override
public void handleFault() {
appendToErrorMessage("Sending DepositTxPublishedMessage failed");
takerTrade.setErrorMessage(errorMessage);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -0,0 +1,85 @@
/*
* 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.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerSendsFiatTransferStartedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsFiatTransferStartedMessage.class);
public TakerSendsFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
FiatTransferStartedMessage tradeMessage = new FiatTransferStartedMessage(takerTradeProcessModel.getId(),
takerTradeProcessModel.taker.getPayoutTxSignature(),
takerTradeProcessModel.offerer.getPayoutAmount(),
takerTradeProcessModel.taker.getPayoutAmount(),
takerTradeProcessModel.taker.getAddressEntry().getAddressString());
takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), tradeMessage,
takerTradeProcessModel.taker.getP2pSigPubKey(),
takerTradeProcessModel.taker.getP2pEncryptPubKey(),
new SendMessageListener() {
@Override
public void handleResult() {
log.trace("Sending FiatTransferStartedMessage succeeded.");
if (takerTrade instanceof TakerAsBuyerTrade) {
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.FIAT_PAYMENT_STARTED);
}
else if (takerTrade instanceof TakerAsSellerTrade) {
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.FIAT_PAYMENT_STARTED);
}
complete();
}
@Override
public void handleFault() {
appendToErrorMessage("Sending FiatTransferStartedMessage failed");
takerTrade.setErrorMessage(errorMessage);
if (takerTrade instanceof TakerAsBuyerTrade) {
((TakerAsBuyerTrade) takerTrade).setProcessState(TakerAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
}
else if (takerTrade instanceof TakerAsSellerTrade) {
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
}
failed();
}
});
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

View file

@ -19,16 +19,18 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendPayoutTxPublishedMessage extends TakerTradeTask { public class TakerSendsPayoutTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxPublishedMessage.class); private static final Logger log = LoggerFactory.getLogger(TakerSendsPayoutTxPublishedMessage.class);
public SendPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) { public TakerSendsPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }
@ -51,7 +53,12 @@ public class SendPayoutTxPublishedMessage extends TakerTradeTask {
public void handleFault() { public void handleFault() {
appendToErrorMessage("Sending PayoutTxPublishedMessage failed"); appendToErrorMessage("Sending PayoutTxPublishedMessage failed");
takerTrade.setErrorMessage(errorMessage); takerTrade.setErrorMessage(errorMessage);
takerTrade.setProcessState(TakerTrade.TakerProcessState.MESSAGE_SENDING_FAILED);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed(); failed();
} }
}); });

View file

@ -19,6 +19,8 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
@ -27,10 +29,10 @@ import javafx.application.Platform;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendRequestDepositTxInputsMessage extends TakerTradeTask { public class TakerSendsRequestDepositTxInputsMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendRequestDepositTxInputsMessage.class); private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestDepositTxInputsMessage.class);
public SendRequestDepositTxInputsMessage(TaskRunner taskHandler, TakerTrade model) { public TakerSendsRequestDepositTxInputsMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }
@ -60,7 +62,7 @@ public class SendRequestDepositTxInputsMessage extends TakerTradeTask {
// We try to repeat once and if that fails as well we persist the state for a later retry. // We try to repeat once and if that fails as well we persist the state for a later retry.
if (retryCounter == 0) { if (retryCounter == 0) {
retryCounter++; retryCounter++;
Platform.runLater(SendRequestDepositTxInputsMessage.this::doRun); Platform.runLater(TakerSendsRequestDepositTxInputsMessage.this::doRun);
} }
else { else {
appendToErrorMessage("Sending TakeOfferFeePayedMessage to offerer failed. Maybe the network connection was " + appendToErrorMessage("Sending TakeOfferFeePayedMessage to offerer failed. Maybe the network connection was " +
@ -68,7 +70,12 @@ public class SendRequestDepositTxInputsMessage extends TakerTradeTask {
"or cancel that trade."); "or cancel that trade.");
takerTrade.setErrorMessage(errorMessage); takerTrade.setErrorMessage(errorMessage);
takerTrade.setProcessState(TakerTrade.TakerProcessState.MESSAGE_SENDING_FAILED);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed(); failed();
} }

View file

@ -0,0 +1,83 @@
/*
* 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.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerSendsRequestPayDepositMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestPayDepositMessage.class);
public TakerSendsRequestPayDepositMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
RequestPayDepositMessage tradeMessage = new RequestPayDepositMessage(
takerTradeProcessModel.getId(),
takerTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.taker.getOutputs(),
takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.taker.getP2pSigPubKey(),
takerTradeProcessModel.taker.getP2pEncryptPubKey(),
takerTradeProcessModel.taker.getFiatAccount(),
takerTradeProcessModel.taker.getAccountId());
takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
complete();
}
@Override
public void handleFault() {
appendToErrorMessage("Sending RequestTakerDepositPaymentMessage failed");
takerTrade.setErrorMessage(errorMessage);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
if (takerTrade instanceof TakerAsBuyerTrade) {
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
}
else if (takerTrade instanceof TakerAsSellerTrade) {
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
}
failed(t);
}
}
}

View file

@ -19,16 +19,18 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener; import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendRequestPublishDepositTxMessage extends TakerTradeTask { public class TakerSendsRequestPublishDepositTxMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendRequestPublishDepositTxMessage.class); private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestPublishDepositTxMessage.class);
public SendRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade model) { public TakerSendsRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
} }
@ -58,7 +60,11 @@ public class SendRequestPublishDepositTxMessage extends TakerTradeTask {
public void handleFault() { public void handleFault() {
appendToErrorMessage("Sending RequestOffererPublishDepositTxMessage failed"); appendToErrorMessage("Sending RequestOffererPublishDepositTxMessage failed");
takerTrade.setErrorMessage(errorMessage); takerTrade.setErrorMessage(errorMessage);
takerTrade.setProcessState(TakerTrade.TakerProcessState.MESSAGE_SENDING_FAILED);
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.MESSAGE_SENDING_FAILED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.MESSAGE_SENDING_FAILED);
failed(); failed();
} }

View file

@ -0,0 +1,89 @@
/*
* 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.btc.FeePolicy;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerSignsAndPublishDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSignsAndPublishDepositTx.class);
public TakerSignsAndPublishDepositTx(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
}
@Override
protected void doRun() {
try {
Coin inputAmount = takerTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
takerTradeProcessModel.getTradeWalletService().signAndPublishDepositTx(
takerTradeProcessModel.offerer.getPreparedDepositTx(),
takerTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.taker.getOutputs(),
inputAmount,
takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("takerSignAndPublishTx succeeded " + transaction);
takerTrade.setDepositTx(transaction);
if (takerTrade instanceof TakerAsBuyerTrade) {
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED);
takerTrade.setLifeCycleState(TakerAsBuyerTrade.LifeCycleState.PENDING);
}
else if (takerTrade instanceof TakerAsSellerTrade) {
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.DEPOSIT_PUBLISHED);
takerTrade.setLifeCycleState(TakerAsSellerTrade.LifeCycleState.PENDING);
}
complete();
}
@Override
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
});
} catch (Throwable t) {
t.printStackTrace();
takerTrade.setThrowable(t);
failed(t);
}
}
}

Some files were not shown because too many files have changed in this diff Show more