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);
}
public void offererSignsAndPublishDepositTx(Transaction takersPreparedDepositTx,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> takerConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs,
Coin offererInputAmount,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException,
public void signAndPublishDepositTx(Transaction preparedDepositTx,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> takerConnectedOutputsForAllInputs,
List<TransactionOutput> buyerOutputs,
Coin buyerInputAmount,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException,
WalletException {
log.trace("offererSignsAndPublishTx called");
log.trace("takersPreparedDepositTx " + takersPreparedDepositTx.toString());
log.trace("preparedDepositTx " + preparedDepositTx.toString());
log.trace("offererConnectedOutputsForAllInputs " + offererConnectedOutputsForAllInputs.toString());
log.trace("takerConnectedOutputsForAllInputs " + takerConnectedOutputsForAllInputs.toString());
log.trace("offererOutputs " + offererOutputs.toString());
log.trace("offererInputAmount " + offererInputAmount.toFriendlyString());
log.trace("buyerOutputs " + buyerOutputs.toString());
log.trace("buyerInputAmount " + buyerInputAmount.toFriendlyString());
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
@ -335,10 +335,10 @@ public class TradeWalletService {
// Check if takers Multisig script is identical to mine
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");
// 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
Transaction depositTx = new Transaction(params);
@ -358,8 +358,8 @@ public class TradeWalletService {
for (TransactionOutput connectedOutputForInput : takerConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
// We grab the signature from the takersPreparedDepositTx and apply it to the new tx input
TransactionInput takerInput = takersPreparedDepositTx.getInputs().get(offererConnectedOutputsForAllInputs.size());
// We grab the signature from the preparedDepositTx and apply it to the new tx input
TransactionInput takerInput = preparedDepositTx.getInputs().get(offererConnectedOutputsForAllInputs.size());
byte[] scriptProgram = takerInput.getScriptSig().getProgram();
if (scriptProgram.length == 0)
throw new TransactionVerificationException("Inputs from taker not singed.");
@ -368,8 +368,8 @@ public class TradeWalletService {
depositTx.addInput(transactionInput);
}
// Add all outputs from takersPreparedDepositTx to depositTx
takersPreparedDepositTx.getOutputs().forEach(depositTx::addOutput);
// Add all outputs from preparedDepositTx to depositTx
preparedDepositTx.getOutputs().forEach(depositTx::addOutput);
// Sign inputs
for (int i = 0; i < offererConnectedOutputsForAllInputs.size(); i++) {
@ -379,11 +379,11 @@ public class TradeWalletService {
}
// 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());
}
if (offererInputAmount.compareTo(offererSpendingAmount) != 0)
if (buyerInputAmount.compareTo(offererSpendingAmount) != 0)
throw new TransactionVerificationException("Offerers input amount does not match required value.");
verifyTransaction(depositTx);
@ -416,37 +416,37 @@ public class TradeWalletService {
return wallet.getTransaction(tx.getHash());
}
public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
AddressEntry offererAddressEntry,
String takerPayoutAddressString,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey)
public byte[] createAndSignPayoutTx(Transaction depositTx,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
AddressEntry buyerAddressEntry,
String sellerPayoutAddressString,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey)
throws AddressFormatException, TransactionVerificationException, SigningException {
log.trace("offererCreatesAndSignsPayoutTx called");
log.trace("depositTx " + depositTx.toString());
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
log.trace("offererAddressEntry " + offererAddressEntry.toString());
log.trace("takerPayoutAddressString " + takerPayoutAddressString);
log.trace("buyerAddressEntry " + buyerAddressEntry.toString());
log.trace("sellerPayoutAddressString " + sellerPayoutAddressString);
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).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");
Transaction preparedPayoutTx = createPayoutTx(depositTx,
offererPayoutAmount,
takerPayoutAmount,
offererAddressEntry.getAddressString(),
takerPayoutAddressString);
buyerAddressEntry.getAddressString(),
sellerPayoutAddressString);
// MS redeemScript
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
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);
@ -459,40 +459,40 @@ public class TradeWalletService {
return offererSignature.encodeToDER();
}
public void takerSignsAndPublishPayoutTx(Transaction depositTx,
byte[] offererSignature,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
String offererAddressString,
AddressEntry takerAddressEntry,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback)
public void signAndPublishPayoutTx(Transaction depositTx,
byte[] buyerSignature,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
String buyerAddressString,
AddressEntry sellerAddressEntry,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback)
throws AddressFormatException, TransactionVerificationException, WalletException, SigningException {
log.trace("takerSignsAndPublishPayoutTx called");
log.trace("depositTx " + depositTx.toString());
log.trace("offererSignature r " + ECKey.ECDSASignature.decodeFromDER(offererSignature).r.toString());
log.trace("offererSignature s " + ECKey.ECDSASignature.decodeFromDER(offererSignature).s.toString());
log.trace("buyerSignature r " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).r.toString());
log.trace("buyerSignature s " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).s.toString());
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
log.trace("offererAddressString " + offererAddressString);
log.trace("takerAddressEntry " + takerAddressEntry);
log.trace("buyerAddressString " + buyerAddressString);
log.trace("sellerAddressEntry " + sellerAddressEntry);
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).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");
Transaction payoutTx = createPayoutTx(depositTx,
offererPayoutAmount,
takerPayoutAmount,
offererAddressString,
takerAddressEntry.getAddressString());
buyerAddressString,
sellerAddressEntry.getAddressString());
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
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 s " + takerSignature.s.toString());
@ -500,7 +500,7 @@ public class TradeWalletService {
Sha256Hash hashForSignature = payoutTx.hashForSignature(0, redeemScript.getProgram(), (byte) 1);
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);
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
// Take care of order of signatures. See comment below at getMultiSigRedeemScript

View File

@ -45,7 +45,7 @@ public class TaskRunner<T extends Model> {
this.resultHandler = resultHandler;
this.errorMessageHandler = errorMessageHandler;
}
public final void addTasks(Class<? extends Task<? extends Model>>... items) {
List<Class<? extends Task<? extends Model>>> list = Arrays.asList(items);
tasks.addAll(list);
@ -61,7 +61,19 @@ public class TaskRunner<T extends Model> {
try {
currentTask = tasks.poll();
log.trace("Run task: " + currentTask.getSimpleName());
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass()).newInstance(this, sharedModel).run();
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();
} catch (Throwable throwable) {
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass().getSuperclass()).newInstance(this, sharedModel).run();
}
} catch (Throwable throwable) {
throwable.printStackTrace();
handleErrorMessage("Error at taskRunner: " + throwable.getMessage());

View File

@ -22,6 +22,7 @@ lower gradient color on tab: dddddd
.root {
-bs-grey: #666666;
-bs-bg-grey: #dddddd;
-bs-bg-green: #00aa33;
-bs-error-red: #dd0000;
-fx-accent: #0f87c3;
@ -466,6 +467,42 @@ textfield */
-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 */
#titled-group-bg-label {
-fx-font-weight: bold;

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@
* 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.DataModel;
@ -33,7 +33,7 @@ import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
class IrcAccountDataModel implements Activatable, DataModel {
class AltCoinAccountDataModel implements Activatable, DataModel {
private final User user;
@ -48,7 +48,7 @@ class IrcAccountDataModel implements Activatable, DataModel {
@Inject
public IrcAccountDataModel(User user) {
public AltCoinAccountDataModel(User user) {
this.user = user;
}

View File

@ -24,7 +24,7 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?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"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="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/>.
*/
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.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.
*/
@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 InputTextField ircNickNameTextField;
@ -51,7 +51,7 @@ public class IrcAccountView extends ActivatableViewAndModel<GridPane, IrcAccount
private Wizard wizard;
@Inject
public IrcAccountView(IrcAccountViewModel model) {
public AltCoinAccountView(AltCoinAccountViewModel model) {
super(model);
}

View File

@ -15,7 +15,7 @@
* 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.ViewModel;
@ -36,7 +36,7 @@ import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.util.StringConverter;
class IrcAccountViewModel extends ActivatableWithDataModel<IrcAccountDataModel> implements ViewModel {
class AltCoinAccountViewModel extends ActivatableWithDataModel<AltCoinAccountDataModel> implements ViewModel {
private final InputValidator nickNameValidator;
@ -46,7 +46,7 @@ class IrcAccountViewModel extends ActivatableWithDataModel<IrcAccountDataModel>
final ObjectProperty<FiatAccount.Type> type = new SimpleObjectProperty<>();
@Inject
public IrcAccountViewModel(IrcAccountDataModel dataModel, BankAccountNumberValidator nickNameValidator) {
public AltCoinAccountViewModel(AltCoinAccountDataModel dataModel, BankAccountNumberValidator nickNameValidator) {
super(dataModel);
this.nickNameValidator = nickNameValidator;

View File

@ -17,7 +17,6 @@
package io.bitsquare.gui.main.account.settings;
import io.bitsquare.BitsquareException;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.CachingViewLoader;
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.account.AccountView;
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.restrictions.RestrictionsView;
import io.bitsquare.gui.main.account.content.seedwords.SeedWordsView;
@ -52,7 +51,7 @@ public class AccountSettingsView extends ActivatableViewAndModel {
private final ViewLoader viewLoader;
private final Navigation navigation;
private MenuItem seedWords, password, restrictions, ircAccount, registration;
private MenuItem seedWords, password, restrictions, fiatAccount, registration;
private Navigation.Listener listener;
@FXML private VBox leftVBox;
@ -77,15 +76,10 @@ public class AccountSettingsView extends ActivatableViewAndModel {
seedWords = new MenuItem(navigation, toggleGroup, "Wallet seed", SeedWordsView.class);
password = new MenuItem(navigation, toggleGroup, "Wallet password", ChangePasswordView.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);
seedWords.setDisable(true);
password.setDisable(true);
restrictions.setDisable(true);
registration.setDisable(true);
leftVBox.getChildren().addAll(seedWords, password, restrictions, ircAccount, registration);
leftVBox.getChildren().addAll(seedWords, password, restrictions, fiatAccount, registration);
}
@Override
@ -93,7 +87,7 @@ public class AccountSettingsView extends ActivatableViewAndModel {
navigation.addListener(listener);
ViewPath viewPath = navigation.getCurrentPath();
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) {
loadView(viewPath.get(3));
@ -114,9 +108,8 @@ public class AccountSettingsView extends ActivatableViewAndModel {
if (view instanceof SeedWordsView) seedWords.setSelected(true);
else if (view instanceof ChangePasswordView) password.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 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.gui.Navigation;
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.registration.RegistrationView;
import io.bitsquare.gui.main.account.content.restrictions.RestrictionsView;
@ -46,7 +46,7 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
@FXML VBox leftVBox;
@FXML AnchorPane content;
private WizardItem seedWords, password, ircAccount, restrictions, registration;
private WizardItem seedWords, password, fiatAccount, restrictions, registration;
private Navigation.Listener listener;
private final ViewLoader viewLoader;
@ -78,17 +78,17 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
password.onCompleted();
restrictions.show();
}
else if (viewClass == IrcAccountView.class) {
else if (viewClass == FiatAccountView.class) {
seedWords.onCompleted();
password.onCompleted();
restrictions.onCompleted();
ircAccount.show();
fiatAccount.show();
}
else if (viewClass == RegistrationView.class) {
seedWords.onCompleted();
password.onCompleted();
restrictions.onCompleted();
ircAccount.onCompleted();
fiatAccount.onCompleted();
registration.show();
}
};
@ -99,23 +99,18 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
"Setup password", "Protect your wallet with a password");
restrictions = new WizardItem(RestrictionsView.class,
"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");
registration = new WizardItem(RegistrationView.class,
"Register your account", "The registration in the Blockchain requires a payment of 0.0002 BTC");
leftVBox.getChildren().addAll(seedWords, password, restrictions, ircAccount, registration);
seedWords.setDisable(true);
password.setDisable(true);
restrictions.setDisable(true);
registration.setDisable(true);
leftVBox.getChildren().addAll(seedWords, password, restrictions, fiatAccount, registration);
}
@Override
public void activate() {
navigation.addListener(listener);
ircAccount.show();
seedWords.show();
}
@Override
@ -135,10 +130,10 @@ public class AccountSetupWizard extends ActivatableView implements Wizard {
}
else if (currentStep instanceof RestrictionsView) {
restrictions.onCompleted();
ircAccount.show();
fiatAccount.show();
}
else if (currentStep instanceof IrcAccountView) {
ircAccount.onCompleted();
else if (currentStep instanceof FiatAccountView) {
fiatAccount.onCompleted();
registration.show();
}
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.CreateOfferFeeTx;
import io.bitsquare.trade.protocol.placeoffer.tasks.ValidateOffer;
import io.bitsquare.trade.protocol.trade.offerer.OffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateAndSignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateOffererDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendRequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract;
import io.bitsquare.trade.protocol.trade.offerer.OffererAsBuyerProtocol;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsRequestSellerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSignsAndPublishDepositTx;
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.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.TakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.TakerAsSellerProtocol;
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.ProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx;
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.TakerProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessRequestSellerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSignsAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
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.VerifyOffererAccount;
@ -100,44 +100,44 @@ public class DebugView extends InitializableView {
/*---- Protocol ----*/
OffererProtocol.class,
ProcessRequestDepositTxInputsMessage.class,
CreateOffererDepositTxInputs.class,
SendRequestTakerDepositPaymentMessage.class,
OffererAsBuyerProtocol.class,
OffererProcessRequestDepositTxInputsMessage.class,
OffererCreatesDepositTxInputs.class,
OffererSendsRequestSellerDepositPaymentMessage.class,
ProcessRequestPublishDepositTxMessage.class,
OffererProcessRequestPublishDepositTxMessage.class,
VerifyTakerAccount.class,
VerifyAndSignContract.class,
SignAndPublishDepositTx.class,
SendDepositTxPublishedMessage.class,
OffererVerifiesAndSignsContract.class,
OffererSignsAndPublishDepositTx.class,
OffererSendsDepositTxPublishedMessage.class,
CreateAndSignPayoutTx.class,
OffererCreatesAndSignPayoutTx.class,
VerifyTakeOfferFeePayment.class,
SendFiatTransferStartedMessage.class,
OffererSendsFiatTransferStartedMessage.class,
ProcessPayoutTxPublishedMessage.class,
OffererProcessPayoutTxPublishedMessage.class,
Boolean.class, /* used as seperator*/
/*---- Protocol ----*/
TakerProtocol.class,
TakerAsSellerProtocol.class,
CreateTakeOfferFeeTx.class,
SendRequestDepositTxInputsMessage.class,
TakerSendsRequestDepositTxInputsMessage.class,
ProcessRequestTakerDepositPaymentMessage.class,
TakerProcessRequestSellerDepositPaymentMessage.class,
VerifyOffererAccount.class,
CreateAndSignContract.class,
CreateAndSignDepositTx.class,
SendRequestPublishDepositTxMessage.class,
TakerCreatesAndSignContract.class,
TakerCreatesAndSignsDepositTx.class,
TakerSendsRequestPublishDepositTxMessage.class,
ProcessDepositTxPublishedMessage.class,
CommitDepositTx.class,
TakerProcessDepositTxPublishedMessage.class,
TakerCommitDepositTx.class,
ProcessFiatTransferStartedMessage.class,
TakerProcessFiatTransferStartedMessage.class,
SignAndPublishPayoutTx.class,
TakerSignsAndPublishPayoutTx.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.ViewModel;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.Trade;
import com.google.inject.Inject;
@ -71,8 +71,8 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
String getState(ClosedTradesListItem item) {
if (item != null && item.getTrade() != null) {
Trade.LifeCycleState lifeCycleState = item.getTrade().lifeCycleStateProperty().get();
if (lifeCycleState instanceof TakerTrade.TakerLifeCycleState) {
switch ((TakerTrade.TakerLifeCycleState) lifeCycleState) {
if (lifeCycleState instanceof TakerAsBuyerTrade.LifeCycleState) {
switch ((TakerAsBuyerTrade.LifeCycleState) lifeCycleState) {
case COMPLETED:
return "Completed";
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.");
}
}
else if (lifeCycleState instanceof OffererTrade.OffererLifeCycleState) {
switch ((OffererTrade.OffererLifeCycleState) lifeCycleState) {
else if (lifeCycleState instanceof OffererAsSellerTrade.LifeCycleState) {
switch ((OffererAsSellerTrade.LifeCycleState) lifeCycleState) {
case OFFER_CANCELED:
return "Canceled";
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 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.gui.components.Popups;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
@ -35,6 +37,8 @@ import com.google.inject.Inject;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
@ -65,8 +69,8 @@ class PendingTradesDataModel implements Activatable, DataModel {
final StringProperty txId = new SimpleStringProperty();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<TakerTrade.TakerProcessState> takerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<OffererTrade.OffererProcessState> offererProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade.ProcessState> takerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade.ProcessState> offererProcessState = new SimpleObjectProperty<>();
@Inject
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) {
@ -115,10 +119,10 @@ class PendingTradesDataModel implements Activatable, DataModel {
isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
Trade trade = getTrade();
if (trade instanceof TakerTrade)
takerProcessState.bind(((TakerTrade) trade).processStateProperty());
if (trade instanceof TakerAsSellerTrade)
takerProcessState.bind(trade.processStateProperty());
else
offererProcessState.bind(((OffererTrade) trade).processStateProperty());
offererProcessState.bind(trade.processStateProperty());
log.trace("selectTrade trade.stateProperty().get() " + trade.processStateProperty().get());
@ -127,11 +131,11 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
void fiatPaymentStarted() {
((OffererTrade) getTrade()).onFiatPaymentStarted();
((OffererAsBuyerTrade) getTrade()).onFiatPaymentStarted();
}
void fiatPaymentReceived() {
((TakerTrade) getTrade()).onFiatPaymentReceived();
((TakerAsSellerTrade) getTrade()).onFiatPaymentReceived();
}
void withdraw(String toAddress) {
@ -180,8 +184,9 @@ class PendingTradesDataModel implements Activatable, DataModel {
return isOfferer;
}
@Nullable
Trade getTrade() {
return selectedItem.getTrade();
return selectedItem != null ? selectedItem.getTrade() : null;
}
Coin getTotalFees() {

View File

@ -17,6 +17,8 @@
package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade;
import org.bitcoinj.core.Coin;
@ -51,11 +53,17 @@ public class PendingTradesListItem {
}
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return trade.tradeAmountProperty();
if (trade instanceof TakerTrade)
return ((TakerTrade) trade).tradeAmountProperty();
else
return ((OffererTrade) trade).tradeAmountProperty();
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return trade.tradeVolumeProperty();
if (trade instanceof TakerTrade)
return ((TakerTrade) trade).tradeVolumeProperty();
else
return ((OffererTrade) trade).tradeVolumeProperty();
}
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.validation.BtcAddressValidator;
import io.bitsquare.locale.BSResources;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
@ -240,79 +242,160 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
}
private void updateTakerState() {
TakerTrade.TakerProcessState 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;
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 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_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 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;
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;
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);
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;
}
}
}
}
private void updateOffererState() {
OffererTrade.OffererProcessState processState = dataModel.offererProcessState.get();
log.debug("updateOffererState " + processState);
if (processState != null) {
switch (processState) {
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.OFFERER_BUYER_START_PAYMENT);
break;
if (dataModel.getTrade() instanceof OffererAsBuyerTrade) {
OffererAsBuyerTrade.ProcessState processState = (OffererAsBuyerTrade.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 FIAT_PAYMENT_STARTED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
break;
case PAYOUT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_COMPLETED);
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;
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;
default:
log.warn("unhandled viewState " + processState);
break;
}
}
}
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.gui.Navigation;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.trade.createoffer.CreateOfferView;
import io.bitsquare.gui.main.trade.offerbook.OfferBookView;
@ -128,13 +127,6 @@ public abstract class TradeView extends ActivatableView<TabPane, Void> {
OfferActionHandler offerActionHandler = new OfferActionHandler() {
@Override
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.price = price;
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
// in different graphs
takeOfferView = (TakeOfferView) view;
takeOfferView.initWithData(direction, amount, offer);
takeOfferView.initWithData(amount, offer);
takeOfferPane = ((TakeOfferView) view).getRoot();
final Tab tab = new Tab("Take offer");
takeOfferView.setCloseHandler(() -> {

View File

@ -75,7 +75,7 @@ class CreateOfferDataModel implements Activatable, DataModel {
private final String offerId;
@Nullable private Offer.Direction direction = null;
private Offer.Direction direction;
private AddressEntry addressEntry;
final StringProperty requestPlaceOfferErrorMessage = new SimpleStringProperty();
@ -211,8 +211,12 @@ class CreateOfferDataModel implements Activatable, DataModel {
}
void calculateTotalToPay() {
if (securityDepositAsCoin.get() != null)
totalToPayAsCoin.set(offerFeeAsCoin.get().add(networkFeeAsCoin.get()).add(securityDepositAsCoin.get()));
if (securityDepositAsCoin.get() != null) {
if (direction == Offer.Direction.BUY)
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;
}
@SuppressWarnings("NullableProblems")
void setDirection(Offer.Direction direction) {
// direction can not be changed once it is initially set
checkNotNull(direction);
this.direction = direction;
}
WalletService getWalletService() {
return walletService;
}
@ -270,4 +267,9 @@ class CreateOfferDataModel implements Activatable, DataModel {
public Boolean 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"/>
</GridPane.margin>
<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">
<padding>
<Insets top="-5.0"/>
@ -64,7 +64,7 @@
<Insets right="10.0" top="20.0"/>
</GridPane.margin>
<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"/>
<HBox>
<InputTextField fx:id="amountTextField" id="text-input-with-currency-text-field"
@ -125,8 +125,7 @@
</HBox>
</VBox>
<InfoDisplay gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"
text="%createOffer.amountPriceBox.info"/>
<InfoDisplay fx:id="amountPriceBoxInfo" gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"/>
<Button fx:id="showPaymentInfoScreenButton" text="%createOffer.amountPriceBox.next" id="show-details-button"
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.portfolio.PortfolioView;
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.util.ImageUtil;
import io.bitsquare.locale.BSResources;
@ -80,14 +81,14 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
@FXML AddressTextField addressTextField;
@FXML BalanceTextField balanceTextField;
@FXML ProgressIndicator placeOfferSpinner;
@FXML InfoDisplay advancedInfoDisplay, fundsBoxInfoDisplay;
@FXML InfoDisplay amountPriceBoxInfo, advancedInfoDisplay, fundsBoxInfoDisplay;
@FXML TitledGroupBg priceAmountPane, payFundsPane, showDetailsPane;
@FXML Button showPaymentInfoScreenButton, showAdvancedSettingsButton, placeOfferButton;
@FXML InputTextField amountTextField, minAmountTextField, priceTextField, volumeTextField;
@FXML TextField acceptedArbitratorsTextField, totalToPayTextField, bankAccountTypeTextField,
bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField,
acceptedLanguagesTextField;
@FXML Label buyLabel, addressLabel, balanceLabel, totalToPayLabel, totalToPayInfoIconLabel, bankAccountTypeLabel,
@FXML Label buyLabel, amountToTradeLabel, addressLabel, balanceLabel, totalToPayLabel, totalToPayInfoIconLabel, bankAccountTypeLabel,
bankAccountCurrencyLabel, bankAccountCountyLabel, acceptedCountriesLabel, acceptedCountriesLabelIcon,
acceptedLanguagesLabel, acceptedLanguagesLabelIcon, acceptedArbitratorsLabel,
acceptedArbitratorsLabelIcon, amountBtcLabel, priceFiatLabel, volumeFiatLabel, minAmountBtcLabel,
@ -116,8 +117,8 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
protected void initialize() {
setupListeners();
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()));
}
@ -292,10 +293,10 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
model.showTransactionPublishedScreen.addListener((o, oldValue, newValue) -> {
// TODO temp just for testing
// newValue = false;
// close();
//navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class, OffersView.class);
newValue = false;
close();
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class, OffersView.class);
if (newValue) {
overlayManager.blurContent();
@ -336,20 +337,17 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
minAmountBtcLabel.textProperty().bind(model.btcCode);
priceDescriptionLabel.textProperty().bind(createStringBinding(() ->
BSResources.get("createOffer.amountPriceBox.priceDescription",
model.fiatCode.get()),
model.fiatCode));
volumeDescriptionLabel.textProperty().bind(createStringBinding(() ->
BSResources.get("createOffer.amountPriceBox.volumeDescription",
model.fiatCode.get()),
model.fiatCode));
BSResources.get("createOffer.amountPriceBox.priceDescription", model.fiatCode.get()), model.fiatCode));
volumeDescriptionLabel.textProperty().bind(createStringBinding(() -> model.volumeDescriptionLabel.get(), model.fiatCode, model.volumeDescriptionLabel));
buyLabel.textProperty().bind(model.directionLabel);
amountToTradeLabel.textProperty().bind(model.amountToTradeLabel);
amountTextField.textProperty().bindBidirectional(model.amount);
minAmountTextField.textProperty().bindBidirectional(model.minAmount);
priceTextField.textProperty().bindBidirectional(model.price);
volumeTextField.textProperty().bindBidirectional(model.volume);
amountPriceBoxInfo.textProperty().bind(model.amountPriceBoxInfo);
totalToPayTextField.textProperty().bind(model.totalToPay);
@ -471,19 +469,25 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
infoGridPane.setVgap(5);
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"),
model.securityDeposit.get());
addPayInfoEntry(infoGridPane, 1, BSResources.get("createOffer.fundsBox.offerFee"),
addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.offerFee"),
model.offerFee.get());
addPayInfoEntry(infoGridPane, 2, BSResources.get("createOffer.fundsBox.networkFee"),
addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.networkFee"),
model.networkFee.get());
Separator separator = new Separator();
separator.setOrientation(Orientation.HORIZONTAL);
separator.setStyle("-fx-background: #666;");
GridPane.setConstraints(separator, 1, 3);
GridPane.setConstraints(separator, 1, i++);
infoGridPane.getChildren().add(separator);
addPayInfoEntry(infoGridPane, 4, BSResources.get("createOffer.fundsBox.total"),
addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.total"),
model.totalToPay.get());
totalToPayInfoPopover = new PopOver(infoGridPane);
if (totalToPayInfoIconLabel.getScene() != null) {

View File

@ -50,13 +50,18 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
private final BSFormatter formatter;
private final FiatValidator fiatValidator;
final StringProperty amount = new SimpleStringProperty();
final StringProperty minAmount = new SimpleStringProperty();
final StringProperty price = new SimpleStringProperty();
final StringProperty volume = new SimpleStringProperty();
final StringProperty volumeDescriptionLabel = new SimpleStringProperty();
final StringProperty amountPriceBoxInfo = new SimpleStringProperty();
final StringProperty securityDeposit = new SimpleStringProperty();
final StringProperty tradeAmount = new SimpleStringProperty();
final StringProperty totalToPay = new SimpleStringProperty();
final StringProperty directionLabel = new SimpleStringProperty();
final StringProperty amountToTradeLabel = new SimpleStringProperty();
final StringProperty offerFee = new SimpleStringProperty();
final StringProperty networkFee = new SimpleStringProperty();
final StringProperty bankAccountType = new SimpleStringProperty();
@ -113,9 +118,21 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
// setOfferBookFilter is a one time call
void initWithData(Offer.Direction direction, Coin amount, Fiat price) {
dataModel.setDirection(direction);
directionLabel.set(dataModel.getDirection() == Offer.Direction.BUY ? BSResources.get("shared.buy") : BSResources.get
("shared.sell"));
dataModel.initWithData( direction, amount, price);
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
boolean amountValid = false;
@ -327,6 +344,9 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
securityDeposit.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.securityDepositAsCoin.get()),
dataModel.securityDepositAsCoin));
tradeAmount.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.amountAsCoin.get()),
dataModel.amountAsCoin));
totalToPayAsCoin.bind(dataModel.totalToPayAsCoin);
offerFee.bind(createStringBinding(() -> formatter.formatCoinWithCode(dataModel.offerFeeAsCoin.get()),
@ -407,4 +427,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
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();
//TODO temp for testing
/* amountTextField.setText("1");
amountTextField.setText("1");
priceTextField.setText("300");
volumeTextField.setText("300");*/
volumeTextField.setText("300");
}
@Override
@ -227,8 +227,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer);
}
else {
Popups.openInfoPopup("Not implemented yet",
"At the moment you can only take offers in the Sell BTC screen.");
offerActionHandler.takeOffer(model.getAmountAsCoin(), model.getPriceAsCoin(), offer);
}
}
else {

View File

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

View File

@ -67,8 +67,7 @@
<Insets right="10.0" top="20.0"/>
</GridPane.margin>
<VBox spacing="4">
<Label id="input-description-label" text="%takeOffer.amountPriceBox.amountDescription"
prefWidth="170"/>
<Label fx:id="amountDescriptionLabel" id="input-description-label" prefWidth="170"/>
<HBox>
<InputTextField fx:id="amountTextField" id="text-input-with-currency-text-field"
promptText="%takeOffer.amount.prompt" prefWidth="170"
@ -120,8 +119,7 @@
style=" -fx-alignment: center;"/>
</VBox>
<InfoDisplay gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"
text="%takeOffer.amountPriceBox.info"/>
<InfoDisplay fx:id="amountPriceBoxInfoDisplay" gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"/>
<Label fx:id="isOfferAvailableLabel" text="%takeOffer.fundsBox.isOfferAvailable" GridPane.rowIndex="3">
<GridPane.margin>
@ -179,8 +177,7 @@
</GridPane.margin>
</BalanceTextField>
<InfoDisplay fx:id="fundsBoxInfoDisplay" gridPane="$gridPane" onAction="#onOpenFundingHelp" rowIndex="7"
text="%takeOffer.fundsBox.info" visible="false"/>
<InfoDisplay fx:id="fundsBoxInfoDisplay" gridPane="$gridPane" onAction="#onOpenFundingHelp" rowIndex="7" visible="false"/>
<HBox spacing="10" GridPane.columnIndex="1" GridPane.rowIndex="8">
<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.dialog.Dialog;
import static javafx.beans.binding.Bindings.createStringBinding;
@FxmlView
public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOfferViewModel> {
@ -76,13 +78,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
@FXML AddressTextField addressTextField;
@FXML BalanceTextField balanceTextField;
@FXML ProgressIndicator takeOfferSpinner, isOfferAvailableProgressIndicator;
@FXML InfoDisplay advancedInfoDisplay, fundsBoxInfoDisplay;
@FXML InfoDisplay amountPriceBoxInfoDisplay, advancedInfoDisplay, fundsBoxInfoDisplay;
@FXML TitledGroupBg priceAmountPane, payFundsPane, showDetailsPane;
@FXML Button showPaymentInfoScreenButton, showAdvancedSettingsButton, takeOfferButton;
@FXML TextField priceTextField, volumeTextField, acceptedArbitratorsTextField, totalToPayTextField,
bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField,
acceptedCountriesTextField, acceptedLanguagesTextField;
@FXML Label isOfferAvailableLabel, buyLabel, addressLabel, amountRangeTextField, balanceLabel, totalToPayLabel,
@FXML Label isOfferAvailableLabel, buyLabel, addressLabel, amountDescriptionLabel, amountRangeTextField, balanceLabel, totalToPayLabel,
totalToPayInfoIconLabel,
bankAccountTypeLabel, bankAccountCurrencyLabel, bankAccountCountyLabel, acceptedCountriesLabel,
acceptedLanguagesLabel, acceptedArbitratorsLabel, amountBtcLabel, priceDescriptionLabel,
@ -118,16 +120,17 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
model.errorMessage.removeListener(errorMessageChangeListener);
}
public void initWithData(Offer.Direction direction, Coin amount, Offer offer) {
model.initWithData(direction, amount, offer);
public void initWithData(Coin amount, Offer offer) {
model.initWithData(amount, offer);
if (direction == Offer.Direction.BUY)
if (offer.getDirection() == Offer.Direction.SELL)
imageView.setId("image-buy-large");
else
imageView.setId("image-sell-large");
priceDescriptionLabel.setText(BSResources.get("takeOffer.amountPriceBox.priceDescription", 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());
@ -144,6 +147,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
acceptedLanguagesTextField.setText(model.getAcceptedLanguages());
acceptedArbitratorsTextField.setText(model.getAcceptedArbitratorIds());
amountPriceBoxInfoDisplay.textProperty().bind(model.amountPriceBoxInfo);
fundsBoxInfoDisplay.textProperty().bind(model.fundsBoxInfoDisplay);
showCheckAvailabilityScreen();
}
@ -243,9 +248,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
model.showTransactionPublishedScreen.addListener((o, oldValue, newValue) -> {
// TODO temp just for testing
/* newValue = false;
close();*/
//navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
newValue = false;
close();
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
if (newValue) {
overlayManager.blurContent();
@ -287,7 +292,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
volumeTextField.textProperty().bindBidirectional(model.volume);
totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.totalToPayAsCoin);
amountDescriptionLabel.textProperty().bind(model.amountDescription);
// Validation
amountTextField.validationResultProperty().bind(model.amountValidationResult);
@ -429,22 +436,27 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
infoGridPane.setVgap(5);
infoGridPane.setPadding(new Insets(10, 10, 10, 10));
addPayInfoEntry(infoGridPane, 0,
BSResources.get("takeOffer.fundsBox.amount"),
model.getAmount());
addPayInfoEntry(infoGridPane, 1,
int i = 0;
if (model.isSeller()) {
addPayInfoEntry(infoGridPane, i++,
BSResources.get("takeOffer.fundsBox.amount"),
model.getAmount());
}
addPayInfoEntry(infoGridPane, i++,
BSResources.get("takeOffer.fundsBox.securityDeposit"),
model.securityDeposit.get());
addPayInfoEntry(infoGridPane, 2, BSResources.get("takeOffer.fundsBox.offerFee"),
addPayInfoEntry(infoGridPane, i++, BSResources.get("takeOffer.fundsBox.offerFee"),
model.getOfferFee());
addPayInfoEntry(infoGridPane, 3, BSResources.get("takeOffer.fundsBox.networkFee"),
addPayInfoEntry(infoGridPane, i++, BSResources.get("takeOffer.fundsBox.networkFee"),
model.getNetworkFee());
Separator separator = new Separator();
separator.setOrientation(Orientation.HORIZONTAL);
separator.setStyle("-fx-background: #666;");
GridPane.setConstraints(separator, 1, 4);
GridPane.setConstraints(separator, 1, i++);
infoGridPane.getChildren().add(separator);
addPayInfoEntry(infoGridPane, 5, BSResources.get("takeOffer.fundsBox.total"),
addPayInfoEntry(infoGridPane, i++, BSResources.get("takeOffer.fundsBox.total"),
model.totalToPay.get());
totalToPayInfoPopover = new PopOver(infoGridPane);
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.CurrencyUtil;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
@ -54,7 +56,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
DETAILS_SCREEN
}
private String fiatCode;
private String amountRange;
private String price;
private String directionLabel;
@ -85,7 +86,11 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
final StringProperty transactionId = new SimpleStringProperty();
final StringProperty errorMessage = 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 isTakeOfferSpinnerVisible = new SimpleBooleanProperty(false);
@ -115,18 +120,31 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
}
// 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);
directionLabel = direction == Offer.Direction.BUY ?
BSResources.get("shared.buy") : BSResources.get("shared.sell");
directionLabel = offer.getDirection() == Offer.Direction.SELL ?
BSResources.get("shared.buyBitcoin") : BSResources.get("shared.sellBitcoin");
fiatCode = offer.getCurrencyCode();
fiatCode.set(offer.getCurrencyCode());
if (!dataModel.isMinAmountLessOrEqualAmount()) {
amountValidationResult.set(new InputValidator.ValidationResult(false,
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()));
amountRange = formatter.formatCoinWithCode(offer.getMinAmount()) + " - " +
@ -210,39 +228,74 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
dataModel.takeOffer((takerTrade) -> {
takerTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("takerTrade state = " + newValue);
String msg = "";
if (takerTrade.getErrorMessage() != null)
msg = "\nError message: " + takerTrade.getErrorMessage();
switch (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 (takerTrade instanceof TakerAsBuyerTrade) {
switch ((TakerAsBuyerTrade.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;
}
}
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) {
@ -255,6 +308,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
});
}
boolean isSeller() {
return dataModel.getDirection() == Offer.Direction.BUY;
}
void securityDepositInfoDisplayed() {
dataModel.securityDepositInfoDisplayed();
}
@ -307,7 +364,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
}
String getFiatCode() {
return fiatCode;
return fiatCode.get();
}
String getAmount() {

View File

@ -24,6 +24,6 @@ public class Colors {
public static final Paint LIGHT_GREY = Color.valueOf("#CCCCCC");
public static final Paint MID_GREY = Color.valueOf("#666666");
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.storage.Storage;
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 org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionConfidence;
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.ObjectInputStream;
import java.io.Serializable;
@ -43,12 +36,10 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
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.
private static final long serialVersionUID = 1L;
@ -59,26 +50,10 @@ public class OffererTrade extends Trade implements Serializable {
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public enum OffererLifeCycleState implements LifeCycleState {
OFFER_OPEN,
OFFER_RESERVED,
OFFER_CANCELED,
PENDING,
COMPLETED,
FAILED
public interface LifeCycleState extends Trade.LifeCycleState {
}
public enum OffererProcessState implements ProcessState {
UNDEFINED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
EXCEPTION
public interface ProcessState extends Trade.ProcessState {
}
@ -86,31 +61,23 @@ public class OffererTrade extends Trade implements Serializable {
// Fields
///////////////////////////////////////////////////////////////////////////////////////////
// Transient/Immutable
transient private ObjectProperty<OffererProcessState> processStateProperty;
transient private ObjectProperty<OffererLifeCycleState> lifeCycleStateProperty;
// Mutable
private Coin tradeAmount;
private Peer tradingPeer;
private OffererProcessState processState;
private OffererLifeCycleState lifeCycleState;
protected Coin tradeAmount;
protected Peer tradingPeer;
transient protected ObjectProperty<Coin> tradeAmountProperty;
transient protected ObjectProperty<Fiat> tradeVolumeProperty;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public OffererTrade(Offer offer, Storage<? extends TradeList> storage) {
protected OffererTrade(Offer offer, Storage<? extends TradeList> storage) {
super(offer, storage);
log.trace("Created by constructor");
processState = OffererProcessState.UNDEFINED;
lifeCycleState = OffererLifeCycleState.OFFER_OPEN;
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
initStates();
initStateProperties();
tradeAmountProperty = new SimpleObjectProperty<>();
tradeVolumeProperty = new SimpleObjectProperty<>();
}
@ -119,87 +86,24 @@ public class OffererTrade extends Trade implements Serializable {
in.defaultReadObject();
log.trace("Created from serialized form.");
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>();
tradeVolumeProperty = new SimpleObjectProperty<>();
if (tradeAmount != null) {
tradeAmountProperty.set(tradeAmount);
tradeVolumeProperty.set(getTradeVolume());
}
initStateProperties();
initAmountProperty();
}
@Override
protected ProcessModel createProcessModel() {
public ProcessModel createProcessModel() {
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
///////////////////////////////////////////////////////////////////////////////////////////
public OffererProcessModel getProcessModel() {
return (OffererProcessModel) processModel;
}
public void setTradingPeer(Peer tradingPeer) {
this.tradingPeer = tradingPeer;
}
@ -230,30 +134,27 @@ public class OffererTrade extends Trade implements Serializable {
return null;
}
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return tradeAmountProperty;
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return tradeVolumeProperty;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void setupConfidenceListener() {
assert depositTx != null;
TransactionConfidence transactionConfidence = depositTx.getConfidence();
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);
}
protected void initAmountProperty() {
tradeAmountProperty = new SimpleObjectProperty<>();
tradeVolumeProperty = new SimpleObjectProperty<>();
@Override
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
Throwables.propagate(t);
}
});
if (tradeAmount != null) {
tradeAmountProperty.set(tradeAmount);
tradeVolumeProperty.set(getTradeVolume());
}
}
@Override
@ -261,8 +162,6 @@ public class OffererTrade extends Trade implements Serializable {
return "OffererTrade{" +
"tradeAmount=" + tradeAmount +
", tradingPeer=" + tradingPeer +
", processState=" + processState +
", lifeCycleState=" + lifeCycleState +
'}';
super.toString();
}
}

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.storage.Storage;
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 org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionConfidence;
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.Serializable;
@ -40,12 +33,10 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
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.
private static final long serialVersionUID = 1L;
@ -56,28 +47,10 @@ public class TakerTrade extends Trade implements Serializable {
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public enum TakerLifeCycleState implements LifeCycleState {
PENDING,
COMPLETED,
FAILED
public interface LifeCycleState extends Trade.LifeCycleState {
}
public enum TakerProcessState implements 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
public interface ProcessState extends Trade.ProcessState {
}
@ -85,78 +58,43 @@ public class TakerTrade extends Trade implements Serializable {
// Fields
///////////////////////////////////////////////////////////////////////////////////////////
// Transient/Immutable
transient private ObjectProperty<TakerProcessState> processStateProperty;
transient private ObjectProperty<TakerLifeCycleState> lifeCycleStateProperty;
// Immutable
private final Coin tradeAmount;
private final Peer tradingPeer;
// Mutable
private TakerProcessState processState;
private TakerLifeCycleState lifeCycleState;
protected final Coin tradeAmount;
protected final Peer tradingPeer;
transient protected ObjectProperty<Coin> tradeAmountProperty;
transient protected ObjectProperty<Fiat> tradeVolumeProperty;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public TakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer,
Storage<? extends TradeList> storage) {
protected TakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer,
Storage<? extends TradeList> storage) {
super(offer, storage);
log.trace("Created by constructor");
this.tradeAmount = tradeAmount;
this.tradingPeer = tradingPeer;
processState = TakerProcessState.UNDEFINED;
lifeCycleState = TakerLifeCycleState.PENDING;
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
initStates();
initStateProperties();
initAmountProperty();
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
initStateProperties();
initAmountProperty();
}
@Override
protected ProcessModel createProcessModel() {
public ProcessModel createProcessModel() {
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
///////////////////////////////////////////////////////////////////////////////////////////
@ -175,70 +113,26 @@ public class TakerTrade extends Trade implements Serializable {
return tradingPeer;
}
@Override
public ReadOnlyObjectProperty<TakerProcessState> processStateProperty() {
return processStateProperty;
}
@Override
public ReadOnlyObjectProperty<TakerLifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
}
public TakerProcessModel getProcessModel() {
return (TakerProcessModel) processModel;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setLifeCycleState(TakerLifeCycleState lifeCycleState) {
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return tradeAmountProperty;
}
public void setProcessState(TakerProcessState processState) {
this.processState = processState;
processStateProperty.set(processState);
if (processState == TakerProcessState.EXCEPTION) {
setLifeCycleState(TakerLifeCycleState.FAILED);
disposeProtocol();
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return tradeVolumeProperty;
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(TakerTrade.TakerProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void setupConfidenceListener() {
assert depositTx != null;
TransactionConfidence transactionConfidence = depositTx.getConfidence();
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);
}
});
protected void initAmountProperty() {
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
}
@Override
@ -246,8 +140,6 @@ public class TakerTrade extends Trade implements Serializable {
return "TakerTrade{" +
"tradeAmount=" + tradeAmount +
", tradingPeer=" + tradingPeer +
", processState=" + processState +
", lifeCycleState=" + lifeCycleState +
'}';
super.toString();
}
}

View File

@ -33,8 +33,14 @@ import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
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.ObjectInputStream;
import java.io.Serializable;
@ -45,6 +51,9 @@ import javax.annotation.Nullable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -64,10 +73,10 @@ abstract public class Trade extends Model implements Serializable {
// 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 protected ObjectProperty<ProcessState> processStateProperty;
transient protected ObjectProperty<LifeCycleState> lifeCycleStateProperty;
transient private Storage<? extends TradeList> storage;
transient protected Protocol protocol;
@ -85,6 +97,8 @@ abstract public class Trade extends Model implements Serializable {
protected final ProcessModel processModel;
// Mutable
protected ProcessState processState;
protected LifeCycleState lifeCycleState;
private MailboxMessage mailboxMessage;
protected Transaction depositTx;
private Contract contract;
@ -96,15 +110,13 @@ abstract public class Trade extends Model implements Serializable {
// Transient/Mutable
transient private String errorMessage;
transient private Throwable throwable;
transient protected ObjectProperty<Coin> tradeAmountProperty;
transient protected ObjectProperty<Fiat> tradeVolumeProperty;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
Trade(Offer offer, Storage<? extends TradeList> storage) {
protected Trade(Offer offer, Storage<? extends TradeList> storage) {
log.trace("Created by constructor");
this.offer = offer;
this.storage = storage;
@ -141,18 +153,6 @@ abstract public class Trade extends Model implements Serializable {
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.
public void updateDepositTxFromWallet(TradeWalletService tradeWalletService) {
@ -163,6 +163,7 @@ abstract public class Trade extends Model implements Serializable {
public void setDepositTx(Transaction tx) {
this.depositTx = tx;
setupConfidenceListener();
storage.queueUpForSave();
}
public void disposeProtocol() {
@ -180,7 +181,57 @@ abstract public class Trade extends Model implements Serializable {
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();
}
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return tradeAmountProperty;
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return tradeVolumeProperty;
}
@Nullable
abstract public Coin getTradeAmount();
@Nullable
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
public String toString() {
return "Trade{" +
"throwable=" + throwable +
return ", protocol=" + protocol +
", offer=" + offer +
", date=" + date +
", processModel=" + processModel +
", processState=" + processState +
", lifeCycleState=" + lifeCycleState +
", mailboxMessage=" + mailboxMessage +
", depositTx=" + depositTx +
", contract=" + contract +
", contractAsJson='" + contractAsJson + '\'' +
", takerContractSignature='" + takerContractSignature + '\'' +
", offererContractSignature='" + offererContractSignature + '\'' +
", payoutTx=" + payoutTx +
", 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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -90,7 +91,7 @@ public class TradeManager {
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
private final Storage<TradeList> pendingTradesStorage;
private final Storage<TradeList> openOfferTradesStorage;
private final TradeList<OffererTrade> openOfferTrades;
private final TradeList<OffererAsBuyerTrade> openOfferTrades;
private final TradeList<Trade> pendingTrades;
private final TradeList<Trade> closedTrades;
@ -149,24 +150,42 @@ public class TradeManager {
// 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.
public void onAllServicesInitialized() {
for (OffererTrade offererTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer();
for (OffererAsBuyerTrade OffererAsBuyerTrade : openOfferTrades) {
Offer offer = OffererAsBuyerTrade.getOffer();
// We add own offers to offerbook when we go online again
offerBookService.addOffer(offer,
() -> log.debug("Successful removed open offer from DHT"),
(message, throwable) -> log.error("Remove open offer from DHT failed. " + message));
setupDepositPublishedListener(offererTrade);
offererTrade.setStorage(openOfferTradesStorage);
initTrade(offererTrade);
setupDepositPublishedListener(OffererAsBuyerTrade);
OffererAsBuyerTrade.setStorage(openOfferTradesStorage);
initTrade(OffererAsBuyerTrade);
}
List<Trade> failedTrades = new ArrayList<>();
for (Trade trade : pendingTrades) {
// 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
// continue the trade, but that might fail.
trade.setStorage(pendingTradesStorage);
trade.updateDepositTxFromWallet(tradeWalletService);
initTrade(trade);
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.updateDepositTxFromWallet(tradeWalletService);
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
@ -210,8 +229,8 @@ public class TradeManager {
log.debug("shutDown");
shutDownRequested = true;
// we remove own offers form offerbook when we go offline
for (OffererTrade offererTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer();
for (OffererAsBuyerTrade OffererAsBuyerTrade : openOfferTrades) {
Offer offer = OffererAsBuyerTrade.getOffer();
offerBookService.removeOfferAtShutDown(offer);
}
}
@ -258,23 +277,23 @@ public class TradeManager {
}
private void handlePlaceOfferResult(Transaction transaction, Offer offer, TransactionResultHandler resultHandler) {
OffererTrade offererTrade = new OffererTrade(offer, openOfferTradesStorage);
openOfferTrades.add(offererTrade);
initTrade(offererTrade);
setupDepositPublishedListener(offererTrade);
OffererAsBuyerTrade offererAsBuyerTrade = new OffererAsBuyerTrade(offer, openOfferTradesStorage);
openOfferTrades.add(offererAsBuyerTrade);
initTrade(offererAsBuyerTrade);
setupDepositPublishedListener(offererAsBuyerTrade);
resultHandler.handleResult(transaction);
}
private void setupDepositPublishedListener(OffererTrade offererTrade) {
offererTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("offererTrade state = " + newValue);
if (newValue == OffererTrade.OffererProcessState.DEPOSIT_PUBLISHED) {
removeOpenOffer(offererTrade.getOffer(),
private void setupDepositPublishedListener(OffererAsBuyerTrade offererAsBuyerTrade) {
offererAsBuyerTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("OffererAsBuyerTrade state = " + newValue);
if (newValue == OffererAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED) {
removeOpenOffer(offererAsBuyerTrade.getOffer(),
() -> log.debug("remove offer was successful"),
log::error,
false);
pendingTrades.add(offererTrade);
offererTrade.setStorage(pendingTradesStorage);
pendingTrades.add(offererAsBuyerTrade);
offererAsBuyerTrade.setStorage(pendingTradesStorage);
}
});
}
@ -290,15 +309,15 @@ public class TradeManager {
offerBookService.removeOffer(offer,
() -> {
offer.setState(Offer.State.REMOVED);
Optional<OffererTrade> offererTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny();
if (offererTradeOptional.isPresent()) {
OffererTrade offererTrade = offererTradeOptional.get();
openOfferTrades.remove(offererTrade);
Optional<OffererAsBuyerTrade> OffererAsBuyerTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny();
if (OffererAsBuyerTradeOptional.isPresent()) {
OffererAsBuyerTrade offererAsBuyerTrade = OffererAsBuyerTradeOptional.get();
openOfferTrades.remove(offererAsBuyerTrade);
if (isCancelRequest) {
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_CANCELED);
closedTrades.add(offererTrade);
offererTrade.disposeProtocol();
offererAsBuyerTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_CANCELED);
closedTrades.add(offererAsBuyerTrade);
offererAsBuyerTrade.disposeProtocol();
}
}
@ -351,7 +370,7 @@ public class TradeManager {
takeOfferResultHandler) {
disposeCheckOfferAvailabilityRequest(offer);
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);
pendingTrades.add(takerTrade);
takerTrade.takeAvailableOffer();
@ -371,7 +390,7 @@ public class TradeManager {
// TODO handle overpaid securityDeposit
Coin amountToWithdraw = trade.getSecurityDeposit();
assert trade.getTradeAmount() != null;
if (trade instanceof OffererTrade)
if (trade instanceof OffererAsBuyerTrade)
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@ -379,10 +398,10 @@ public class TradeManager {
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) {
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
if (trade instanceof OffererTrade)
((OffererTrade) trade).setLifeCycleState(OffererTrade.OffererLifeCycleState.COMPLETED);
if (trade instanceof OffererAsBuyerTrade)
((OffererAsBuyerTrade) trade).setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.COMPLETED);
else
((TakerTrade) trade).setLifeCycleState(TakerTrade.TakerLifeCycleState.COMPLETED);
((TakerAsSellerTrade) trade).setLifeCycleState(TakerAsSellerTrade.LifeCycleState.COMPLETED);
pendingTrades.remove(trade);
closedTrades.add(trade);
@ -421,7 +440,7 @@ public class TradeManager {
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public ObservableList<OffererTrade> getOpenOfferTrades() {
public ObservableList<OffererAsBuyerTrade> getOpenOfferTrades() {
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.
private static final long serialVersionUID = 1L;
public final byte[] offererSignature;
public final byte[] buyerSignature;
public final Coin offererPayoutAmount;
public final Coin takerPayoutAmount;
public final String offererPayoutAddress;
public final String buyerPayoutAddress;
public FiatTransferStartedMessage(String tradeId,
byte[] offererSignature,
byte[] buyerSignature,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
String offererPayoutAddress) {
String buyerPayoutAddress) {
super(tradeId);
this.offererSignature = offererSignature;
this.buyerSignature = buyerSignature;
this.offererPayoutAmount = offererPayoutAmount;
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.Peer;
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.availability.messages.ReportOfferAvailabilityMessage;
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.TradeMessage;
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.CreateAndSignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateOffererDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendRequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCommitsPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsRequestSellerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSignsAndPublishDepositTx;
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.VerifyTakerAccount;
@ -51,21 +51,21 @@ import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.*;
public class OffererProtocol implements Protocol {
private static final Logger log = LoggerFactory.getLogger(OffererProtocol.class);
public class OffererAsBuyerProtocol implements Protocol {
private static final Logger log = LoggerFactory.getLogger(OffererAsBuyerProtocol.class);
private final MessageHandler messageHandler;
private final OffererTrade offererTrade;
private MessageHandler messageHandler;
private final OffererAsBuyerTrade offererAsBuyerTrade;
private final OffererProcessModel offererTradeProcessModel;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public OffererProtocol(OffererTrade model) {
public OffererAsBuyerProtocol(OffererAsBuyerTrade model) {
log.debug("New OffererProtocol " + this);
this.offererTrade = model;
offererTradeProcessModel = offererTrade.getProcessModel();
this.offererAsBuyerTrade = model;
offererTradeProcessModel = offererAsBuyerTrade.getProcessModel();
messageHandler = this::handleMessage;
offererTradeProcessModel.getMessageService().addMessageHandler(messageHandler);
@ -90,7 +90,10 @@ public class OffererProtocol implements Protocol {
public void cleanup() {
log.debug("cleanup " + this);
offererTradeProcessModel.getMessageService().removeMessageHandler(messageHandler);
if (messageHandler != null) {
offererTradeProcessModel.getMessageService().removeMessageHandler(messageHandler);
messageHandler = null;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -106,7 +109,7 @@ public class OffererProtocol implements Protocol {
// to take the
// offer
// 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);
offererTradeProcessModel.getMessageService().sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
@Override
@ -131,16 +134,17 @@ public class OffererProtocol implements Protocol {
private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) {
checkTradeId(offererTradeProcessModel.getId(), tradeMessage);
offererTradeProcessModel.setTradeMessage(tradeMessage);
offererTrade.setTradingPeer(taker);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_RESERVED);
offererAsBuyerTrade.setTradingPeer(taker);
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade,
offererAsBuyerTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_RESERVED);
TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> log.debug("taskRunner at handleRequestDepositTxInputsMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
ProcessRequestDepositTxInputsMessage.class,
CreateOffererDepositTxInputs.class,
SendRequestTakerDepositPaymentMessage.class
OffererProcessRequestDepositTxInputsMessage.class,
OffererCreatesDepositTxInputs.class,
OffererSendsRequestSellerDepositPaymentMessage.class
);
taskRunner.run();
}
@ -148,15 +152,15 @@ public class OffererProtocol implements Protocol {
private void handleRequestPublishDepositTxMessage(RequestPublishDepositTxMessage tradeMessage) {
offererTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade,
TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> log.debug("taskRunner at handleRequestPublishDepositTxMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
ProcessRequestPublishDepositTxMessage.class,
OffererProcessRequestPublishDepositTxMessage.class,
VerifyTakerAccount.class,
VerifyAndSignContract.class,
SignAndPublishDepositTx.class,
SendDepositTxPublishedMessage.class
OffererVerifiesAndSignsContract.class,
OffererSignsAndPublishDepositTx.class,
OffererSendsDepositTxPublishedMessage.class
);
taskRunner.run();
}
@ -168,13 +172,13 @@ public class OffererProtocol implements Protocol {
// User clicked the "bank transfer started" button
public void onFiatPaymentStarted() {
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade,
TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> log.debug("taskRunner at handleBankTransferStartedUIEvent completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
CreateAndSignPayoutTx.class,
VerifyTakeOfferFeePayment.class,
SendFiatTransferStartedMessage.class
OffererCreatesAndSignPayoutTx.class,
OffererSendsFiatTransferStartedMessage.class
);
taskRunner.run();
}
@ -187,7 +191,7 @@ public class OffererProtocol implements Protocol {
private void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage) {
offererTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade,
TaskRunner<OffererAsBuyerTrade> taskRunner = new TaskRunner<>(offererAsBuyerTrade,
() -> {
log.debug("taskRunner at handlePayoutTxPublishedMessage completed");
// we are done!
@ -195,8 +199,8 @@ public class OffererProtocol implements Protocol {
},
this::handleTaskRunnerFault);
taskRunner.addTasks(ProcessPayoutTxPublishedMessage.class);
taskRunner.addTasks(CommitPayoutTx.class);
taskRunner.addTasks(OffererProcessPayoutTxPublishedMessage.class);
taskRunner.addTasks(OffererCommitsPayoutTx.class);
taskRunner.run();
}
@ -211,7 +215,7 @@ public class OffererProtocol implements Protocol {
TradeMessage tradeMessage = (TradeMessage) message;
nonEmptyStringOf(tradeMessage.tradeId);
if (tradeMessage.tradeId.equals(offererTrade.getId())) {
if (tradeMessage.tradeId.equals(offererAsBuyerTrade.getId())) {
if (tradeMessage instanceof RequestIsOfferAvailableMessage) {
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 org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.crypto.DeterministicKey;
@ -36,8 +37,6 @@ import java.security.PublicKey;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -57,7 +56,8 @@ public class Offerer implements Serializable {
private Coin payoutAmount;
private List<TransactionOutput> connectedOutputsForAllInputs;
private List<TransactionOutput> outputs; // used to verify amounts with change outputs
private Transaction preparedDepositTx;
private PublicKey p2pSigPublicKey;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
@ -99,6 +99,10 @@ public class Offerer implements Serializable {
return user.getP2PSigPubKey();
}
public PublicKey getP2pEncryptPublicKey() {
return user.getP2PEncryptPubKey();
}
public PublicKey getP2pEncryptPubKey() {
return user.getP2PEncryptPubKey();
}
@ -124,7 +128,7 @@ public class Offerer implements Serializable {
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Nullable
public List<TransactionOutput> getOutputs() {
return outputs;
}
@ -133,7 +137,6 @@ public class Offerer implements Serializable {
this.outputs = outputs;
}
@Nullable
public byte[] getPayoutTxSignature() {
return payoutTxSignature;
}
@ -142,7 +145,6 @@ public class Offerer implements Serializable {
this.payoutTxSignature = payoutTxSignature;
}
@Nullable
public Coin getPayoutAmount() {
return payoutAmount;
}
@ -151,7 +153,6 @@ public class Offerer implements Serializable {
this.payoutAmount = payoutAmount;
}
@Nullable
public List<TransactionOutput> getConnectedOutputsForAllInputs() {
return connectedOutputsForAllInputs;
}
@ -160,6 +161,22 @@ public class Offerer implements Serializable {
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
public String toString() {
return "Offerer{" +
@ -172,4 +189,6 @@ public class Offerer implements Serializable {
", outputs=" + outputs +
'}';
}
}

View File

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

View File

@ -44,7 +44,7 @@ public class Taker implements Serializable {
// Mutable
private String accountId;
private FiatAccount fiatAccount;
private PublicKey p2pSigPublicKey;
private PublicKey p2pSigPubKey;
private PublicKey p2pEncryptPubKey;
private String contractAsJson;
private String contractSignature;
@ -53,7 +53,8 @@ public class Taker implements Serializable {
private List<TransactionOutput> connectedOutputsForAllInputs;
private String payoutAddressString;
private byte[] tradeWalletPubKey;
private List<TransactionOutput> outputs;
private byte[] signature;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
@ -89,12 +90,12 @@ public class Taker implements Serializable {
this.fiatAccount = fiatAccount;
}
public PublicKey getP2pSigPublicKey() {
return p2pSigPublicKey;
public PublicKey getP2pSigPubKey() {
return p2pSigPubKey;
}
public void setP2pSigPublicKey(PublicKey p2pSigPublicKey) {
this.p2pSigPublicKey = p2pSigPublicKey;
public void setP2pSigPubKey(PublicKey p2pSigPubKey) {
this.p2pSigPubKey = p2pSigPubKey;
}
public PublicKey getP2pEncryptPubKey() {
@ -161,13 +162,28 @@ public class Taker implements Serializable {
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
public String toString() {
return "Taker{" +
"accountId='" + accountId + '\'' +
", fiatAccount=" + fiatAccount +
", p2pSigPublicKey=" + p2pSigPublicKey +
", p2pSigPublicKey=" + p2pSigPubKey +
", p2pEncryptPubKey=" + p2pEncryptPubKey +
", contractAsJson='" + contractAsJson + '\'' +
", contractSignature='" + contractSignature + '\'' +
@ -178,4 +194,6 @@ public class Taker implements Serializable {
", 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.LoggerFactory;
public class CommitPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(CommitPayoutTx.class);
public class OffererCommitsPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCommitsPayoutTx.class);
public CommitPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererCommitsPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}

View File

@ -18,6 +18,7 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Coin;
@ -25,10 +26,10 @@ import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateAndSignPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignPayoutTx.class);
public class OffererCreatesAndSignPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignPayoutTx.class);
public CreateAndSignPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererCreatesAndSignPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -37,10 +38,16 @@ public class CreateAndSignPayoutTx extends OffererTradeTask {
try {
assert offererTrade.getTradeAmount() != null;
Coin securityDeposit = offererTrade.getSecurityDeposit();
Coin offererPayoutAmount = offererTrade.getTradeAmount().add(securityDeposit);
@SuppressWarnings("UnnecessaryLocalVariable") Coin takerPayoutAmount = securityDeposit;
Coin offererPayoutAmount = securityDeposit;
if (offererTrade.getOffer().getDirection() == Offer.Direction.BUY)
offererPayoutAmount = offererPayoutAmount.add(offererTrade.getTradeAmount());
byte[] offererPayoutTxSignature = offererTradeProcessModel.getTradeWalletService().offererCreatesAndSignsPayoutTx(
Coin takerPayoutAmount = securityDeposit;
if (offererTrade.getOffer().getDirection() == Offer.Direction.SELL)
takerPayoutAmount = takerPayoutAmount.add(offererTrade.getTradeAmount());
byte[] offererPayoutTxSignature = offererTradeProcessModel.getTradeWalletService().createAndSignPayoutTx(
offererTrade.getDepositTx(),
offererPayoutAmount,
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.TradeWalletService;
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;
@ -27,10 +29,10 @@ import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateOffererDepositTxInputs extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateOffererDepositTxInputs.class);
public class OffererCreatesDepositTxInputs extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesDepositTxInputs.class);
public CreateOffererDepositTxInputs(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererCreatesDepositTxInputs(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -38,8 +40,8 @@ public class CreateOffererDepositTxInputs extends OffererTradeTask {
protected void doRun() {
try {
log.debug("offererTrade.id" + offererTrade.getId());
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(offererInputAmount,
Coin inputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(inputAmount,
offererTradeProcessModel.offerer.getAddressEntry());
offererTradeProcessModel.offerer.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
@ -49,7 +51,14 @@ public class CreateOffererDepositTxInputs extends OffererTradeTask {
} catch (Throwable t) {
t.printStackTrace();
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);
}
}

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;
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.PayoutTxPublishedMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessPayoutTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessPayoutTxPublishedMessage.class);
public class OffererProcessPayoutTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessPayoutTxPublishedMessage.class);
public ProcessPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererProcessPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -43,8 +45,11 @@ public class ProcessPayoutTxPublishedMessage extends OffererTradeTask {
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();
} catch (Throwable t) {
t.printStackTrace();

View File

@ -18,6 +18,8 @@
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.RequestDepositTxInputsMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*;
public class ProcessRequestDepositTxInputsMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestDepositTxInputsMessage.class);
public class OffererProcessRequestDepositTxInputsMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestDepositTxInputsMessage.class);
public ProcessRequestDepositTxInputsMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererProcessRequestDepositTxInputsMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -49,7 +51,12 @@ public class ProcessRequestDepositTxInputsMessage extends OffererTradeTask {
} catch (Throwable t) {
t.printStackTrace();
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);
}
}

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;
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.RequestPublishDepositTxMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class ProcessRequestPublishDepositTxMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestPublishDepositTxMessage.class);
public class OffererProcessRequestPublishDepositTxMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestPublishDepositTxMessage.class);
public ProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -43,7 +45,7 @@ public class ProcessRequestPublishDepositTxMessage extends OffererTradeTask {
offererTradeProcessModel.taker.setFiatAccount(checkNotNull(message.takerFiatAccount));
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.setContractAsJson(nonEmptyStringOf(message.takerContractAsJson));
offererTradeProcessModel.taker.setContractSignature(nonEmptyStringOf(message.takerContractSignature));
@ -56,7 +58,12 @@ public class ProcessRequestPublishDepositTxMessage extends OffererTradeTask {
} catch (Throwable t) {
t.printStackTrace();
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);
}
}

View File

@ -19,16 +19,18 @@ 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.DepositTxPublishedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendDepositTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendDepositTxPublishedMessage.class);
public class OffererSendsDepositTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsDepositTxPublishedMessage.class);
public SendDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererSendsDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -48,7 +50,12 @@ public class SendDepositTxPublishedMessage extends OffererTradeTask {
public void handleFault() {
appendToErrorMessage("Sending DepositTxPublishedMessage failed");
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();
}
});

View File

@ -19,16 +19,18 @@ 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.FiatTransferStartedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendFiatTransferStartedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendFiatTransferStartedMessage.class);
public class OffererSendsFiatTransferStartedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsFiatTransferStartedMessage.class);
public SendFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererSendsFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -42,13 +44,20 @@ public class SendFiatTransferStartedMessage extends OffererTradeTask {
offererTradeProcessModel.offerer.getAddressEntry().getAddressString());
offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage,
offererTradeProcessModel.taker.getP2pSigPublicKey(),
offererTradeProcessModel.taker.getP2pSigPubKey(),
offererTradeProcessModel.taker.getP2pEncryptPubKey(),
new SendMessageListener() {
@Override
public void handleResult() {
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();
}
@ -56,7 +65,14 @@ public class SendFiatTransferStartedMessage extends OffererTradeTask {
public void handleFault() {
appendToErrorMessage("Sending FiatTransferStartedMessage failed");
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();
}
});

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.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.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendRequestTakerDepositPaymentMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendRequestTakerDepositPaymentMessage.class);
public class OffererSendsRequestPublishDepositTxMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsRequestPublishDepositTxMessage.class);
public SendRequestTakerDepositPaymentMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererSendsRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(
RequestPublishDepositTxMessage tradeMessage = new RequestPublishDepositTxMessage(
offererTradeProcessModel.getId(),
offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.offerer.getOutputs(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.offerer.getP2pEncryptPubKey(),
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() {
@Override
public void handleResult() {
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
complete();
}
@Override
public void handleFault() {
appendToErrorMessage("Sending RequestTakerDepositPaymentMessage failed");
appendToErrorMessage("Sending RequestOffererPublishDepositTxMessage failed");
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();
}
});
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
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;
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;
@ -31,34 +31,35 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishDepositTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
public class OffererSignsAndPublishPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSignsAndPublishPayoutTx.class);
public SignAndPublishDepositTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererSignsAndPublishPayoutTx(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
offererTradeProcessModel.getTradeWalletService().offererSignsAndPublishDepositTx(
offererTradeProcessModel.taker.getPreparedDepositTx(),
offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.offerer.getOutputs(),
offererInputAmount,
offererTradeProcessModel.getTradeWalletService().signAndPublishPayoutTx(
offererTrade.getDepositTx(),
offererTradeProcessModel.taker.getSignature(),
offererTradeProcessModel.offerer.getPayoutAmount(),
offererTradeProcessModel.taker.getPayoutAmount(),
offererTradeProcessModel.taker.getPayoutAddressString(),
offererTradeProcessModel.offerer.getAddressEntry(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.taker.getTradeWalletPubKey(),
offererTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("offererSignAndPublishTx succeeded " + transaction);
offererTradeProcessModel.setPayoutTx(transaction);
offererTrade.setDepositTx(transaction);
offererTrade.setProcessState(OffererTrade.OffererProcessState.DEPOSIT_PUBLISHED);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.PENDING);
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setProcessState(OffererAsBuyerTrade.ProcessState.PAYOUT_PUBLISHED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setProcessState(OffererAsSellerTrade.ProcessState.PAYOUT_PUBLISHED);
complete();
}
@ -67,14 +68,12 @@ public class SignAndPublishDepositTx extends OffererTradeTask {
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
failed(t);
}
});
} catch (Throwable t) {
t.printStackTrace();
offererTrade.setThrowable(t);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_OPEN);
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.trade.Contract;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.util.Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyAndSignContract extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class);
public class OffererVerifiesAndSignsContract extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererVerifiesAndSignsContract.class);
public VerifyAndSignContract(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
public OffererVerifiesAndSignsContract(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
}
@ -44,7 +46,7 @@ public class VerifyAndSignContract extends OffererTradeTask {
offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.taker.getFiatAccount(),
offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.taker.getP2pSigPublicKey());
offererTradeProcessModel.taker.getP2pSigPubKey());
String contractAsJson = Utilities.objectToJson(contract);
String signature = offererTradeProcessModel.getSignatureService().signMessage(offererTradeProcessModel.offerer.getRegistrationKeyPair(),
contractAsJson);
@ -58,7 +60,12 @@ public class VerifyAndSignContract extends OffererTradeTask {
} catch (Throwable t) {
t.printStackTrace();
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);
}
}

View File

@ -18,6 +18,8 @@
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 org.slf4j.Logger;
@ -47,12 +49,21 @@ public class VerifyTakerAccount extends OffererTradeTask {
}
else {
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) {
t.printStackTrace();
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);
}
}

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

View File

@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.models;
import io.bitsquare.fiat.FiatAccount;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import java.io.IOException;
@ -56,6 +57,10 @@ public class Offerer implements Serializable {
private String accountId;
private PublicKey p2pSigPublicKey;
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;
}
@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
public String toString() {

View File

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

View File

@ -18,6 +18,8 @@
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 org.bitcoinj.core.Transaction;
@ -45,9 +47,11 @@ public class BroadcastTakeOfferFeeTx extends TakerTradeTask {
public void onSuccess(Transaction transaction) {
log.debug("Take offer fee published successfully. Transaction ID = " + transaction.getHashAsString());
takerTrade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_PUBLISHED);
complete();
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();
}
@Override
@ -55,7 +59,11 @@ public class BroadcastTakeOfferFeeTx extends TakerTradeTask {
t.printStackTrace();
appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again.");
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);
}

View File

@ -18,6 +18,8 @@
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 org.bitcoinj.core.Transaction;
@ -39,7 +41,11 @@ public class CreateTakeOfferFeeTx extends TakerTradeTask {
.getAddressEntry());
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();
} catch (Throwable t) {

View File

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

View File

@ -27,10 +27,10 @@ import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateAndSignDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignDepositTx.class);
public class TakerCreatesAndSignsDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignsDepositTx.class);
public CreateAndSignDepositTx(TaskRunner taskHandler, TakerTrade model) {
public TakerCreatesAndSignsDepositTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
}
@ -38,7 +38,7 @@ public class CreateAndSignDepositTx extends TakerTradeTask {
protected void doRun() {
try {
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());
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;
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.DepositTxPublishedMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessDepositTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessDepositTxPublishedMessage.class);
public class TakerProcessDepositTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessDepositTxPublishedMessage.class);
public ProcessDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
public TakerProcessDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
}
@ -42,7 +44,11 @@ public class ProcessDepositTxPublishedMessage extends TakerTradeTask {
checkNotNull(message);
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();
} catch (Throwable t) {

View File

@ -18,6 +18,8 @@
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.FiatTransferStartedMessage;
@ -27,10 +29,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*;
public class ProcessFiatTransferStartedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessFiatTransferStartedMessage.class);
public class TakerProcessFiatTransferStartedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessFiatTransferStartedMessage.class);
public ProcessFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade model) {
public TakerProcessFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
}
@ -41,11 +43,15 @@ public class ProcessFiatTransferStartedMessage extends TakerTradeTask {
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTradeProcessModel.offerer.setSignature(checkNotNull(message.offererSignature));
takerTradeProcessModel.offerer.setSignature(checkNotNull(message.buyerSignature));
takerTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
takerTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount)));
takerTradeProcessModel.offerer.setPayoutAddressString(nonEmptyStringOf(message.offererPayoutAddress));
takerTrade.setProcessState(TakerTrade.TakerProcessState.FIAT_PAYMENT_STARTED);
takerTradeProcessModel.offerer.setPayoutAddressString(nonEmptyStringOf(message.buyerPayoutAddress));
if (takerTrade instanceof TakerAsBuyerTrade)
takerTrade.setProcessState(TakerAsBuyerTrade.ProcessState.FIAT_PAYMENT_STARTED);
else if (takerTrade instanceof TakerAsSellerTrade)
takerTrade.setProcessState(TakerAsSellerTrade.ProcessState.FIAT_PAYMENT_STARTED);
complete();
} 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.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.LoggerFactory;
@ -27,28 +27,28 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class ProcessRequestTakerDepositPaymentMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessRequestTakerDepositPaymentMessage.class);
public class TakerProcessRequestSellerDepositPaymentMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessRequestSellerDepositPaymentMessage.class);
public ProcessRequestTakerDepositPaymentMessage(TaskRunner taskHandler, TakerTrade model) {
public TakerProcessRequestSellerDepositPaymentMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
}
@Override
protected void doRun() {
try {
RequestTakerDepositPaymentMessage message = (RequestTakerDepositPaymentMessage) takerTradeProcessModel.getTradeMessage();
RequestPayDepositMessage message = (RequestPayDepositMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTradeProcessModel.offerer.setConnectedOutputsForAllInputs(checkNotNull(message.offererConnectedOutputsForAllInputs));
checkArgument(message.offererConnectedOutputsForAllInputs.size() > 0);
takerTradeProcessModel.offerer.setOutputs(checkNotNull(message.offererOutputs));
takerTradeProcessModel.offerer.setTradeWalletPubKey(checkNotNull(message.offererTradeWalletPubKey));
takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.offererP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.offererP2PEncryptPublicKey));
takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.offererFiatAccount));
takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.offererAccountId));
takerTradeProcessModel.offerer.setConnectedOutputsForAllInputs(checkNotNull(message.buyerConnectedOutputsForAllInputs));
checkArgument(message.buyerConnectedOutputsForAllInputs.size() > 0);
takerTradeProcessModel.offerer.setOutputs(checkNotNull(message.buyerOutputs));
takerTradeProcessModel.offerer.setTradeWalletPubKey(checkNotNull(message.buyerTradeWalletPubKey));
takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.buyerP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.buyerP2PEncryptPublicKey));
takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.buyerFiatAccount));
takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.buyerAccountId));
complete();
} 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.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.PayoutTxPublishedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendPayoutTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxPublishedMessage.class);
public class TakerSendsPayoutTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsPayoutTxPublishedMessage.class);
public SendPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
public TakerSendsPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
}
@ -51,7 +53,12 @@ public class SendPayoutTxPublishedMessage extends TakerTradeTask {
public void handleFault() {
appendToErrorMessage("Sending PayoutTxPublishedMessage failed");
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();
}
});

View File

@ -19,6 +19,8 @@ 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.RequestDepositTxInputsMessage;
@ -27,10 +29,10 @@ import javafx.application.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendRequestDepositTxInputsMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendRequestDepositTxInputsMessage.class);
public class TakerSendsRequestDepositTxInputsMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestDepositTxInputsMessage.class);
public SendRequestDepositTxInputsMessage(TaskRunner taskHandler, TakerTrade model) {
public TakerSendsRequestDepositTxInputsMessage(TaskRunner taskHandler, TakerTrade 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.
if (retryCounter == 0) {
retryCounter++;
Platform.runLater(SendRequestDepositTxInputsMessage.this::doRun);
Platform.runLater(TakerSendsRequestDepositTxInputsMessage.this::doRun);
}
else {
appendToErrorMessage("Sending TakeOfferFeePayedMessage to offerer failed. Maybe the network connection was " +
@ -68,7 +70,12 @@ public class SendRequestDepositTxInputsMessage extends TakerTradeTask {
"or cancel that trade.");
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();
}

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.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.RequestPublishDepositTxMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendRequestPublishDepositTxMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(SendRequestPublishDepositTxMessage.class);
public class TakerSendsRequestPublishDepositTxMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestPublishDepositTxMessage.class);
public SendRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade model) {
public TakerSendsRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
}
@ -58,7 +60,11 @@ public class SendRequestPublishDepositTxMessage extends TakerTradeTask {
public void handleFault() {
appendToErrorMessage("Sending RequestOffererPublishDepositTxMessage failed");
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();
}

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