refactoring trade protocol, reformatting

This commit is contained in:
Manfred Karrer 2014-07-05 15:37:34 +02:00
parent cb4ca6b2a7
commit fd1f23ea62
95 changed files with 2207 additions and 2621 deletions

13
pom.xml
View File

@ -198,17 +198,10 @@
-->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.3.3</version>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>13.0</version>
</dependency>
<!--
<dependency>
<groupId>com.netflix.rxjava</groupId>
<artifactId>rxjava-core</artifactId>
<version>0.5.3</version>
</dependency>
-->
</dependencies>
<reporting>

View File

@ -36,7 +36,9 @@ public class BitSquare extends Application
{
log.debug("Startup: main");
if (args != null && args.length > 0)
{
ID = args[0];
}
launch(args);
}
@ -73,9 +75,13 @@ public class BitSquare extends Application
settings.updateFromStorage((Settings) storage.read(settings.getClass().getName()));
if (ID.isEmpty())
{
stage.setTitle("BitSquare");
}
else
{
stage.setTitle("BitSquare (" + ID + ")");
}
GuiceFXMLLoader.setInjector(injector);
@ -101,7 +107,9 @@ public class BitSquare extends Application
stage.show();
Action response = Popups.openExceptionPopup(e);
if (response == Dialog.Actions.OK)
{
Platform.exit();
}
}
}

View File

@ -16,9 +16,13 @@ class RelayNode
public static void main(String[] args) throws Exception
{
if (args != null && args.length == 1)
{
INSTANCE(new Integer(args[0]));
}
else
{
INSTANCE(5000);
}
}
private static void INSTANCE(int port) throws Exception

View File

@ -26,13 +26,7 @@ public class BankAccount implements Serializable
private final String accountTitle;
public BankAccount(BankAccountType bankAccountType,
Currency currency,
Country country,
String accountTitle,
String accountHolderName,
String accountPrimaryID,
String accountSecondaryID)
public BankAccount(BankAccountType bankAccountType, Currency currency, Country country, String accountTitle, String accountHolderName, String accountPrimaryID, String accountSecondaryID)
{
this.bankAccountType = bankAccountType;
this.currency = currency;
@ -53,9 +47,13 @@ public class BankAccount implements Serializable
public boolean equals(Object obj)
{
if (!(obj instanceof BankAccount))
{
return false;
}
if (obj == this)
{
return true;
}
final BankAccount other = (BankAccount) obj;
return uid.equals(other.getUid());

View File

@ -51,18 +51,28 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
TransactionConfidence conf1 = a.getParentTransaction().getConfidence();
TransactionConfidence conf2 = b.getParentTransaction().getConfidence();
if (conf1.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
depth1 = conf1.getDepthInBlocks();
}
if (conf2.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
depth2 = conf2.getDepthInBlocks();
}
BigInteger aValue = a.getValue();
BigInteger bValue = b.getValue();
BigInteger aCoinDepth = aValue.multiply(BigInteger.valueOf(depth1));
BigInteger bCoinDepth = bValue.multiply(BigInteger.valueOf(depth2));
int c1 = bCoinDepth.compareTo(aCoinDepth);
if (c1 != 0) return c1;
if (c1 != 0)
{
return c1;
}
// The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size.
int c2 = bValue.compareTo(aValue);
if (c2 != 0) return c2;
if (c2 != 0)
{
return c2;
}
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
BigInteger aHash = a.getParentTransaction().getHash().toBigInteger();
BigInteger bHash = b.getParentTransaction().getHash().toBigInteger();
@ -75,11 +85,10 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
// Pick chain-included transactions and transactions that are pending.
TransactionConfidence confidence = tx.getConfidence();
TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
// In regtest mode we expect to have only one peer, so we won't see transactions propagate.
// TODO: The value 1 below dates from a time when transactions we broadcast *to* were counted, set to 0
(confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get());
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) || type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
// In regtest mode we expect to have only one peer, so we won't see transactions propagate.
// TODO: The value 1 below dates from a time when transactions we broadcast *to* were counted, set to 0
(confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get());
}
private static boolean isInBlockChain(Transaction tx)
@ -96,9 +105,13 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
protected boolean shouldSelect(Transaction tx)
{
if (includePending)
{
return isInBlockChainOrPending(tx);
}
else
{
return isInBlockChain(tx);
}
}
@SuppressWarnings("WeakerAccess")
@ -134,11 +147,16 @@ class AddressBasedCoinSelector extends DefaultCoinSelector
long total = 0;
for (TransactionOutput output : sortedOutputs)
{
if (total >= target) break;
if (total >= target)
{
break;
}
// Only pick chain-included transactions, or transactions that are ours and pending.
// Only select outputs from our defined address(es)
if (!shouldSelect(output.getParentTransaction()) || !matchesRequiredAddress(output))
{
continue;
}
selected.add(output);
total += output.getValue().longValue();

View File

@ -63,7 +63,9 @@ public class BitSquareWalletAppKit extends WalletAppKit
vPeerGroup.setBloomFilterFalsePositiveRate(0.001); // 0,1% instead of default 0,05%
if (this.userAgent != null)
{
vPeerGroup.setUserAgent(userAgent, version);
}
if (vWalletFile.exists())
{
walletStream = new FileInputStream(vWalletFile);
@ -71,7 +73,9 @@ public class BitSquareWalletAppKit extends WalletAppKit
addWalletExtensions(); // All extensions must be present before we deserialize
new WalletProtobufSerializer().readWallet(WalletProtobufSerializer.parseToProto(walletStream), vWallet);
if (shouldReplayWallet)
{
vWallet.clearTransactions(0);
}
}
else
{
@ -79,12 +83,18 @@ public class BitSquareWalletAppKit extends WalletAppKit
vWallet.addKey(new ECKey());
addWalletExtensions();
}
if (useAutoSave) vWallet.autosaveToFile(vWalletFile, 1, TimeUnit.SECONDS, null);
if (useAutoSave)
{
vWallet.autosaveToFile(vWalletFile, 1, TimeUnit.SECONDS, null);
}
// Set up peer addresses or discovery first, so if wallet extensions try to broadcast a transaction
// before we're actually connected the broadcast waits for an appropriate number of connections.
if (peerAddresses != null)
{
for (PeerAddress addr : peerAddresses) vPeerGroup.addAddress(addr);
for (PeerAddress addr : peerAddresses)
{
vPeerGroup.addAddress(addr);
}
peerAddresses = null;
}
else
@ -130,27 +140,33 @@ public class BitSquareWalletAppKit extends WalletAppKit
throw new IOException(e);
} finally
{
if (walletStream != null) walletStream.close();
if (walletStream != null)
{
walletStream.close();
}
}
}
private void installShutdownHook()
{
if (autoStop) Runtime.getRuntime().addShutdownHook(new Thread()
if (autoStop)
{
@Override
public void run()
Runtime.getRuntime().addShutdownHook(new Thread()
{
try
@Override
public void run()
{
BitSquareWalletAppKit.this.stopAsync();
BitSquareWalletAppKit.this.awaitTerminated();
try
{
BitSquareWalletAppKit.this.stopAsync();
BitSquareWalletAppKit.this.awaitTerminated();
} catch (Exception e)
{
throw new RuntimeException(e);
} catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
});
});
}
}
}

View File

@ -124,7 +124,9 @@ public class WalletFacade
//walletAppKit.peerGroup().setMaxConnections(11);
if (params == RegTestParams.get())
{
walletAppKit.peerGroup().setMinBroadcastConnections(1);
}
/* else
walletAppKit.peerGroup().setMinBroadcastConnections(2); */
@ -262,7 +264,9 @@ public class WalletFacade
{
AddressEntry arbitratorDepositAddressEntry = getAddressInfoByAddressContext(AddressEntry.AddressContext.ARBITRATOR_DEPOSIT);
if (arbitratorDepositAddressEntry == null)
{
arbitratorDepositAddressEntry = getNewArbitratorDepositAddressEntry();
}
return arbitratorDepositAddressEntry;
}
@ -270,23 +274,37 @@ public class WalletFacade
AddressEntry getUnusedTradeAddressInfo()
{
List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList), addressInfo -> (addressInfo != null && addressInfo.getAddressContext().equals(AddressEntry.AddressContext.TRADE) && addressInfo.getTradeId() == null)));
List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList),
addressInfo -> (addressInfo != null && addressInfo.getAddressContext()
.equals(AddressEntry.AddressContext.TRADE) && addressInfo
.getTradeId() == null)));
if (filteredList != null && !filteredList.isEmpty())
{
return filteredList.get(0);
}
else
{
return getNewTradeAddressEntry();
}
}
private AddressEntry getAddressInfoByAddressContext(AddressEntry.AddressContext addressContext)
{
List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList), addressInfo -> (addressInfo != null && addressInfo.getAddressContext() != null && addressInfo.getAddressContext().equals(addressContext))));
List<AddressEntry> filteredList = Lists.newArrayList(Collections2.filter(ImmutableList.copyOf(addressEntryList),
addressInfo -> (addressInfo != null && addressInfo.getAddressContext() != null && addressInfo.getAddressContext()
.equals(addressContext)
)));
if (filteredList != null && !filteredList.isEmpty())
{
return filteredList.get(0);
}
else
{
return null;
}
}
@ -295,7 +313,9 @@ public class WalletFacade
for (AddressEntry addressEntry : ImmutableList.copyOf(addressEntryList))
{
if (addressEntry.getTradeId() != null && addressEntry.getTradeId().equals(tradeId))
{
return addressEntry;
}
}
AddressEntry addressEntry = getUnusedTradeAddressInfo();
@ -343,7 +363,9 @@ public class WalletFacade
for (AddressEntry addressEntry : addressEntryList)
{
if (addressEntry.getAddressString().equals(address))
{
return addressEntry;
}
}
return null;
}
@ -424,7 +446,9 @@ public class WalletFacade
{
TransactionOutput transactionOutput = transactionInput.getConnectedOutput();
if (transactionOutput != null)
{
connectedOutputs.add(transactionOutput);
}
}
List<TransactionOutput> mergedOutputs = new ArrayList<>();
@ -460,7 +484,9 @@ public class WalletFacade
{
TransactionConfidence transactionConfidence = null;
if (getRegistrationAddressInfo() != null)
{
transactionConfidence = getConfidenceForAddress(getRegistrationAddressInfo().getAddress());
}
return transactionConfidence != null && transactionConfidence.getConfidenceType().equals(TransactionConfidence.ConfidenceType.BUILDING);
}
@ -497,9 +523,13 @@ public class WalletFacade
{
BigInteger balance;
if (balanceListener.getAddress() != null)
{
balance = getBalanceForAddress(balanceListener.getAddress());
}
else
{
balance = getWalletBalance();
}
balanceListener.onBalanceChanged(balance);
}
@ -667,7 +697,11 @@ public class WalletFacade
// 1. step: deposit tx
// Offerer creates the 2of3 multiSig deposit tx with his unsigned input and change output
public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererInputAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey, String tradeId) throws InsufficientMoneyException
public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererInputAmount,
String offererPubKey,
String takerPubKey,
String arbitratorPubKey,
String tradeId) throws InsufficientMoneyException
{
log.debug("offererCreatesMSTxAndAddPayment");
log.trace("inputs: ");
@ -724,8 +758,7 @@ public class WalletFacade
String takerPubKey,
String arbitratorPubKey,
String offerersPartialDepositTxAsHex,
String tradeId
) throws InsufficientMoneyException
String tradeId) throws InsufficientMoneyException
{
log.debug("takerAddPaymentAndSignTx");
log.trace("inputs: ");
@ -782,7 +815,9 @@ public class WalletFacade
// Now we add the inputs and outputs from our temp tx and change the multiSig amount to the correct value
tx.addInput(tempTx.getInput(0));
if (tempTx.getOutputs().size() == 2)
{
tx.addOutput(tempTx.getOutput(1));
}
// We add the btc tx fee to the msOutputAmount and apply the change to the multiSig output
msOutputAmount = msOutputAmount.add(FeePolicy.TX_FEE);
@ -791,7 +826,9 @@ public class WalletFacade
// Now we sign our input
TransactionInput input = tx.getInput(1);
if (input == null || input.getConnectedOutput() == null)
{
log.error("input or input.getConnectedOutput() is null: " + input);
}
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
@ -799,11 +836,17 @@ public class WalletFacade
ECKey.ECDSASignature ecSig = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
}
else if (scriptPubKey.isSentToAddress())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
}
else
{
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
}
log.trace("check if it can be correctly spent for input 1");
input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false);
@ -862,7 +905,8 @@ public class WalletFacade
// add input
Transaction offerersFirstTxConnOut = wallet.getTransaction(offerersFirstTx.getInput(0).getOutpoint().getHash()); // pass that around!
TransactionOutPoint offerersFirstTxOutPoint = new TransactionOutPoint(params, offererTxOutIndex, offerersFirstTxConnOut);
//TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, offerersFirstTx.getInput(0).getScriptBytes(), offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes array
//TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, offerersFirstTx.getInput(0).getScriptBytes(), offerersFirstTxOutPoint); // pass that around! getScriptBytes =
// empty bytes array
TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, new byte[]{}, offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes array
offerersFirstTxInput.setParent(tx);
tx.addInput(offerersFirstTxInput);
@ -884,9 +928,13 @@ public class WalletFacade
// add outputs from takers tx, they are already correct
tx.addOutput(takersSignedTx.getOutput(0));
if (takersSignedTx.getOutputs().size() > 1)
{
tx.addOutput(takersSignedTx.getOutput(1));
}
if (takersSignedTx.getOutputs().size() == 3)
{
tx.addOutput(takersSignedTx.getOutput(2));
}
printInputs("tx", tx);
log.trace("tx = " + tx);
@ -895,7 +943,9 @@ public class WalletFacade
// sign the input
TransactionInput input = tx.getInput(0);
if (input == null || input.getConnectedOutput() == null)
{
log.error("input or input.getConnectedOutput() is null: " + input);
}
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
@ -903,11 +953,17 @@ public class WalletFacade
ECKey.ECDSASignature ecSig = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
}
else if (scriptPubKey.isSentToAddress())
{
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
}
else
{
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
}
input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false);
log.trace("check if it can be correctly spent for input 0 OK");
@ -1089,11 +1145,7 @@ public class WalletFacade
}
private Transaction createPayoutTx(String depositTxAsHex,
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererAddress,
String takerAddress) throws AddressFormatException
private Transaction createPayoutTx(String depositTxAsHex, BigInteger offererPaybackAmount, BigInteger takerPaybackAmount, String offererAddress, String takerAddress) throws AddressFormatException
{
log.trace("createPayoutTx");
log.trace("inputs: ");
@ -1116,10 +1168,16 @@ public class WalletFacade
private void printInputs(String tracePrefix, Transaction tx)
{
for (TransactionInput input : tx.getInputs())
{
if (input.getConnectedOutput() != null)
{
log.trace(tracePrefix + " input value : " + BtcFormatter.formatSatoshis(input.getConnectedOutput().getValue()));
}
else
{
log.trace(tracePrefix + ": " + "Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
}
}
}
@ -1153,13 +1211,17 @@ public class WalletFacade
private void onProgressInUserThread(double percent, int blocksSoFar, final Date date)
{
for (DownloadListener downloadListener : downloadListeners)
{
downloadListener.progress(percent);
}
}
private void onDoneDownloadInUserThread()
{
for (DownloadListener downloadListener : downloadListeners)
{
downloadListener.doneDownload();
}
}
}

View File

@ -48,7 +48,9 @@ public class GuiceFXMLLoader extends FXMLLoader
private void setupControllerFactory()
{
if (GuiceFXMLLoader.injector != null)
{
setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector));
}
}
}

View File

@ -149,7 +149,9 @@ public class MainController implements Initializable, NavigationController
private ChildController loadView(NavigationItem navigationItem)
{
if (childController != null)
{
childController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try
@ -205,7 +207,9 @@ public class MainController implements Initializable, NavigationController
NavigationItem selectedNavigationItem = (NavigationItem) storage.read(this, "selectedNavigationItem");
if (selectedNavigationItem == null)
{
selectedNavigationItem = NavigationItem.HOME;
}
navigateToView(selectedNavigationItem);
}
@ -268,7 +272,9 @@ public class MainController implements Initializable, NavigationController
childController = loadView(navigationItem);
if (childController instanceof MarketController)
{
((MarketController) childController).setDirection(navigationItem == NavigationItem.BUY ? Direction.BUY : Direction.SELL);
}
storage.write(this, "selectedNavigationItem", navigationItem);

View File

@ -104,7 +104,9 @@ public class ArbitratorOverviewController implements Initializable, ChildControl
public ChildController navigateToView(NavigationItem navigationItem)
{
if (arbitratorProfileController != null)
{
arbitratorProfileController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try

View File

@ -28,8 +28,8 @@ public class ArbitratorProfileController implements Initializable, ChildControll
@FXML
private Label nameLabel;
@FXML
private TextField nameTextField, languagesTextField, reputationTextField, maxTradeVolumeTextField, passiveServiceFeeTextField,
arbitrationFeeTextField, methodsTextField, idVerificationsTextField, webPageTextField;
private TextField nameTextField, languagesTextField, reputationTextField, maxTradeVolumeTextField, passiveServiceFeeTextField, arbitrationFeeTextField, methodsTextField,
idVerificationsTextField, webPageTextField;
@FXML
private TextArea descriptionTextArea;

View File

@ -79,8 +79,8 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
@FXML
private ComboBox<Arbitrator.ID_VERIFICATION> idVerificationsComboBox;
@FXML
private TextField nameTextField, idTypeTextField, languagesTextField, maxTradeVolumeTextField, passiveServiceFeeTextField, minPassiveServiceFeeTextField,
arbitrationFeeTextField, minArbitrationFeeTextField, methodsTextField, idVerificationsTextField, webPageTextField, collateralAddressTextField, balanceTextField;
private TextField nameTextField, idTypeTextField, languagesTextField, maxTradeVolumeTextField, passiveServiceFeeTextField, minPassiveServiceFeeTextField, arbitrationFeeTextField,
minArbitrationFeeTextField, methodsTextField, idVerificationsTextField, webPageTextField, collateralAddressTextField, balanceTextField;
@FXML
private TextArea descriptionTextArea;
@FXML
@ -361,11 +361,11 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
private void setupPayCollateralScreen()
{
infoLabel.setText("You need to pay 10 x the max. trading volume as collateral.\n\n" +
"That payment will be locked into a MultiSig fund and be refunded when you leave the arbitration pool.\n" +
"In case of fraud (collusion, not fulfilling the min. dispute quality requirements) you will lose your collateral.\n" +
"If you have a negative feedback from your clients you will lose a part of the collateral,\n" +
"depending on the overall relation of negative to positive ratings you received after a dispute resolution.\n\n" +
"Please pay in " + arbitrator.getMaxTradeVolume() * 10 + " BTC");
"That payment will be locked into a MultiSig fund and be refunded when you leave the arbitration pool.\n" +
"In case of fraud (collusion, not fulfilling the min. dispute quality requirements) you will lose your collateral.\n" +
"If you have a negative feedback from your clients you will lose a part of the collateral,\n" +
"depending on the overall relation of negative to positive ratings you received after a dispute resolution.\n\n" +
"Please pay in " + arbitrator.getMaxTradeVolume() * 10 + " BTC");
String collateralAddress = walletFacade.getRegistrationAddressInfo() != null ? walletFacade.getRegistrationAddressInfo().toString() : "";
@ -467,7 +467,11 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
try
{
BitSquareValidator.textFieldsNotEmptyWithReset(nameTextField, idTypeTextField, languagesTextField, methodsTextField, idVerificationsTextField);
BitSquareValidator.textFieldsHasDoubleValueWithReset(maxTradeVolumeTextField, passiveServiceFeeTextField, minPassiveServiceFeeTextField, arbitrationFeeTextField, minArbitrationFeeTextField);
BitSquareValidator.textFieldsHasDoubleValueWithReset(maxTradeVolumeTextField,
passiveServiceFeeTextField,
minPassiveServiceFeeTextField,
arbitrationFeeTextField,
minArbitrationFeeTextField);
String pubKeyAsHex = walletFacade.getArbitratorDepositAddressInfo().getPubKeyAsHexString();
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey());
@ -483,20 +487,20 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
String description = descriptionTextArea.getText();
return new Arbitrator(pubKeyAsHex,
messagePubKeyAsHex,
name,
idType,
languageList,
new Reputation(),
maxTradeVolume,
passiveServiceFee,
minPassiveServiceFee,
arbitrationFee,
minArbitrationFee,
methodList,
idVerificationList,
webUrl,
description);
messagePubKeyAsHex,
name,
idType,
languageList,
new Reputation(),
maxTradeVolume,
passiveServiceFee,
minPassiveServiceFee,
arbitrationFee,
minArbitrationFee,
methodList,
idVerificationList,
webUrl,
description);
} catch (BitSquareValidator.ValidationException e)
{
return null;

View File

@ -42,7 +42,9 @@ public class LazyLoadingTabPane extends TabPane
public void initialize(NavigationController navigationController, Storage storage, String... tabContentFXMLUrls)
{
if (tabContentFXMLUrls.length == 0)
{
throw new IllegalArgumentException("No tabContentFXMLUrls defined");
}
this.tabContentFXMLUrls = tabContentFXMLUrls;
this.navigationController = navigationController;
@ -59,7 +61,9 @@ public class LazyLoadingTabPane extends TabPane
Object indexObject = storage.read(storageId);
log.trace("saved index" + indexObject);
if (indexObject != null)
{
selectionModel.select((int) indexObject);
}
}
else
{
@ -72,7 +76,9 @@ public class LazyLoadingTabPane extends TabPane
public void cleanup()
{
if (childController != null)
{
childController.cleanup();
}
}
@ -97,7 +103,9 @@ public class LazyLoadingTabPane extends TabPane
if (index < tabContentFXMLUrls.length && index >= 0)
{
if (childController != null)
{
((Hibernate) childController).sleep();
}
Node view = null;
if (index < views.size())

View File

@ -148,12 +148,12 @@ public class ValidatedTextField extends TextField
{
if (t1)
{
// setStyle("-fx-font-weight: bold; -fx-text-fill: red;");
// setStyle("-fx-font-weight: bold; -fx-text-fill: red;");
setEffect(invalidEffect);
}
else
{
// setStyle("-fx-font-weight: normal; -fx-text-fill: inherit;");
// setStyle("-fx-font-weight: normal; -fx-text-fill: inherit;");
setEffect(null);
}
}

View File

@ -91,8 +91,7 @@ public class ConfidenceProgressIndicator extends Control
* Pseudoclass indicating this is a determinate (i.e., progress can be
* determined) progress indicator.
*/
private static final PseudoClass PSEUDO_CLASS_DETERMINATE =
PseudoClass.getPseudoClass("determinate");
private static final PseudoClass PSEUDO_CLASS_DETERMINATE = PseudoClass.getPseudoClass("determinate");
/***************************************************************************
* *
* Properties *
@ -102,8 +101,7 @@ public class ConfidenceProgressIndicator extends Control
* Pseudoclass indicating this is an indeterminate (i.e., progress cannot
* be determined) progress indicator.
*/
private static final PseudoClass PSEUDO_CLASS_INDETERMINATE =
PseudoClass.getPseudoClass("indeterminate");
private static final PseudoClass PSEUDO_CLASS_INDETERMINATE = PseudoClass.getPseudoClass("indeterminate");
/**
* A flag indicating whether it is possible to determine the progress
* of the ProgressIndicator. Typically indeterminate progress bars are

View File

@ -88,37 +88,39 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
* The number of segments in the spinner.
*/
private final IntegerProperty indeterminateSegmentCount =
new StyleableIntegerProperty(8)
private final IntegerProperty indeterminateSegmentCount = new StyleableIntegerProperty(8)
{
@Override
protected void invalidated()
{
if (spinner != null)
{
@Override
protected void invalidated()
{
if (spinner != null) spinner.rebuild();
}
spinner.rebuild();
}
}
@Override
public Object getBean()
{
return ConfidenceProgressIndicatorSkin.this;
}
@Override
public Object getBean()
{
return ConfidenceProgressIndicatorSkin.this;
}
@Override
public String getName()
{
return "indeterminateSegmentCount";
}
@Override
public String getName()
{
return "indeterminateSegmentCount";
}
@Override
public CssMetaData<ConfidenceProgressIndicator, Number> getCssMetaData()
{
return StyleableProperties.INDETERMINATE_SEGMENT_COUNT;
}
};
@Override
public CssMetaData<ConfidenceProgressIndicator, Number> getCssMetaData()
{
return StyleableProperties.INDETERMINATE_SEGMENT_COUNT;
}
};
/**
* True if the progress indicator should rotate as well as animate opacity.
*/
@ -128,7 +130,10 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
@Override
protected void invalidated()
{
if (spinner != null) spinner.setSpinEnabled(get());
if (spinner != null)
{
spinner.setSpinEnabled(get());
}
}
@ -158,47 +163,50 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
* The colour of the progress segment.
*/
private final ObjectProperty<Paint> progressColor =
new StyleableObjectProperty<Paint>(null)
private final ObjectProperty<Paint> progressColor = new StyleableObjectProperty<Paint>(null)
{
@Override
public void set(Paint newProgressColor)
{
final Paint color = (newProgressColor instanceof Color) ? newProgressColor : null;
super.set(color);
}
@Override
protected void invalidated()
{
if (spinner != null)
{
@Override
public void set(Paint newProgressColor)
{
final Paint color = (newProgressColor instanceof Color)
? newProgressColor
: null;
super.set(color);
}
@Override
protected void invalidated()
{
if (spinner != null) spinner.setFillOverride(get());
if (determinateIndicator != null) determinateIndicator.setFillOverride(get());
}
spinner.setFillOverride(get());
}
if (determinateIndicator != null)
{
determinateIndicator.setFillOverride(get());
}
}
@Override
public Object getBean()
{
return ConfidenceProgressIndicatorSkin.this;
}
@Override
public Object getBean()
{
return ConfidenceProgressIndicatorSkin.this;
}
@Override
public String getName()
{
return "progressColorProperty";
}
@Override
public String getName()
{
return "progressColorProperty";
}
@Override
public CssMetaData<ConfidenceProgressIndicator, Paint> getCssMetaData()
{
return StyleableProperties.PROGRESS_COLOR;
}
};
@Override
public CssMetaData<ConfidenceProgressIndicator, Paint> getCssMetaData()
{
return StyleableProperties.PROGRESS_COLOR;
}
};
private boolean timelineNulled = false;
/**
@ -338,8 +346,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
}
@Override
protected void layoutChildren(final double x, final double y,
final double w, final double h)
protected void layoutChildren(final double x, final double y, final double w, final double h)
{
if (spinner != null && getSkinnable().isIndeterminate())
{
@ -509,9 +516,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
final double iRight = snapSize(indicatorInsets.getRight());
final double iTop = snapSize(indicatorInsets.getTop());
final double iBottom = snapSize(indicatorInsets.getBottom());
final double progressRadius = snapSize(Math.min(
Math.min(radius - iLeft, radius - iRight),
Math.min(radius - iTop, radius - iBottom)));
final double progressRadius = snapSize(Math.min(Math.min(radius - iLeft, radius - iRight), Math.min(radius - iTop, radius - iBottom)));
indicatorCircle.setRadius(radius);
indicator.setLayoutX(centerX);
@ -528,9 +533,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
final double pRight = snapSize(progressInsets.getRight());
final double pTop = snapSize(progressInsets.getTop());
final double pBottom = snapSize(progressInsets.getBottom());
final double indicatorRadius = snapSize(Math.min(
Math.min(progressRadius - pLeft, progressRadius - pRight),
Math.min(progressRadius - pTop, progressRadius - pBottom)));
final double indicatorRadius = snapSize(Math.min(Math.min(progressRadius - pLeft, progressRadius - pRight), Math.min(progressRadius - pTop, progressRadius - pBottom)));
// find size of spare box that fits inside indicator radius
double squareBoxHalfWidth = Math.ceil(Math.sqrt((indicatorRadius * indicatorRadius) / 2));
@ -680,9 +683,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
}
for (int i = 100; i <= 3900; i += 100)
{
keyFrames.add(
new KeyFrame(
Duration.millis(i), event -> shiftColors()));
keyFrames.add(new KeyFrame(Duration.millis(i), event -> shiftColors()));
}
indeterminateTimeline.getKeyFrames().setAll(keyFrames);
}
@ -750,7 +751,10 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
private void shiftColors()
{
if (opacities.size() <= 0) return;
if (opacities.size() <= 0)
{
return;
}
final int segments = skin.indeterminateSegmentCount.get();
Collections.rotate(opacities, -1);
for (int i = 0; i < segments; i++)
@ -834,10 +838,7 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
Region region = (Region) child;
if (region.getShape() != null)
{
region.resize(
region.getShape().getLayoutBounds().getMaxX(),
region.getShape().getLayoutBounds().getMaxY()
);
region.resize(region.getShape().getLayoutBounds().getMaxX(), region.getShape().getLayoutBounds().getMaxY());
region.getTransforms().setAll(new Scale(scale, scale, 0, 0));
}
else
@ -857,77 +858,75 @@ public class ConfidenceProgressIndicatorSkin extends BehaviorSkinBase<Confidence
{
public static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
private static final CssMetaData<ConfidenceProgressIndicator, Paint> PROGRESS_COLOR =
new CssMetaData<ConfidenceProgressIndicator, Paint>("-fx-progress-color",
PaintConverter.getInstance(), null)
{
private static final CssMetaData<ConfidenceProgressIndicator, Paint> PROGRESS_COLOR = new CssMetaData<ConfidenceProgressIndicator, Paint>("-fx-progress-color",
PaintConverter.getInstance(),
null)
{
@Override
public boolean isSettable(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return skin.progressColor == null ||
!skin.progressColor.isBound();
}
@Override
public boolean isSettable(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return skin.progressColor == null || !skin.progressColor.isBound();
}
@Override
public StyleableProperty<Paint> getStyleableProperty(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return (StyleableProperty<Paint>) skin.progressColor;
}
};
@Override
public StyleableProperty<Paint> getStyleableProperty(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return (StyleableProperty<Paint>) skin.progressColor;
}
};
private static final CssMetaData<ConfidenceProgressIndicator, Number> INDETERMINATE_SEGMENT_COUNT =
new CssMetaData<ConfidenceProgressIndicator, Number>("-fx-indeterminate-segment-count",
SizeConverter.getInstance(), 8)
{
private static final CssMetaData<ConfidenceProgressIndicator, Number> INDETERMINATE_SEGMENT_COUNT = new CssMetaData<ConfidenceProgressIndicator, Number>("-fx-indeterminate-segment-count",
SizeConverter.getInstance(),
8)
{
@Override
public void set(ConfidenceProgressIndicator node, Number value, StyleOrigin origin)
{
super.set(node, value.intValue(), origin);
}
@Override
public void set(ConfidenceProgressIndicator node, Number value, StyleOrigin origin)
{
super.set(node, value.intValue(), origin);
}
@Override
public boolean isSettable(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return skin.indeterminateSegmentCount == null ||
!skin.indeterminateSegmentCount.isBound();
}
@Override
public boolean isSettable(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return skin.indeterminateSegmentCount == null || !skin.indeterminateSegmentCount.isBound();
}
@Override
public StyleableProperty<Number> getStyleableProperty(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return (StyleableProperty<Number>) skin.indeterminateSegmentCount;
}
};
@Override
public StyleableProperty<Number> getStyleableProperty(ConfidenceProgressIndicator n)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) n.getSkin();
return (StyleableProperty<Number>) skin.indeterminateSegmentCount;
}
};
private static final CssMetaData<ConfidenceProgressIndicator, Boolean> SPIN_ENABLED =
new CssMetaData<ConfidenceProgressIndicator, Boolean>("-fx-spin-enabled",
BooleanConverter.getInstance(), Boolean.FALSE)
{
private static final CssMetaData<ConfidenceProgressIndicator, Boolean> SPIN_ENABLED = new CssMetaData<ConfidenceProgressIndicator, Boolean>("-fx-spin-enabled",
BooleanConverter.getInstance(),
Boolean.FALSE)
{
@Override
public boolean isSettable(ConfidenceProgressIndicator node)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) node.getSkin();
return skin.spinEnabled == null || !skin.spinEnabled.isBound();
}
@Override
public boolean isSettable(ConfidenceProgressIndicator node)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) node.getSkin();
return skin.spinEnabled == null || !skin.spinEnabled.isBound();
}
@Override
public StyleableProperty<Boolean> getStyleableProperty(ConfidenceProgressIndicator node)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) node.getSkin();
return (StyleableProperty<Boolean>) skin.spinEnabled;
}
};
@Override
public StyleableProperty<Boolean> getStyleableProperty(ConfidenceProgressIndicator node)
{
final ConfidenceProgressIndicatorSkin skin = (ConfidenceProgressIndicatorSkin) node.getSkin();
return (StyleableProperty<Boolean>) skin.spinEnabled;
}
};
static
{

View File

@ -37,7 +37,9 @@ public class ProcessStepBar<T> extends Control
{
this.processStepItems = processStepItems;
if (getSkin() != null)
{
((ProcessStepBarSkin) getSkin()).dataChanged();
}
}
public void next()

View File

@ -52,7 +52,9 @@ class ProcessStepBarSkin<T> extends BehaviorSkinBase<ProcessStepBar<T>, Behavior
getChildren().add(labelWithBorder);
labelWithBorders.add(labelWithBorder);
if (i == 0)
{
currentLabelWithBorder = prevLabelWithBorder = labelWithBorder;
}
i++;
}
@ -88,7 +90,9 @@ class ProcessStepBarSkin<T> extends BehaviorSkinBase<ProcessStepBar<T>, Behavior
double newHeight = snapSize(node.prefHeight(-1) + 10);
if (i > 0)
{
x = snapPosition(x - ((LabelWithBorder) node).getArrowWidth());
}
x = snapPosition(x);
y = snapPosition(y);
@ -124,15 +128,13 @@ class ProcessStepBarSkin<T> extends BehaviorSkinBase<ProcessStepBar<T>, Behavior
this.setShape(createButtonShape());
BorderStroke borderStroke = new BorderStroke(Color.LIGHTGRAY, BorderStrokeStyle.SOLID, null,
new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
BorderStroke borderStroke = new BorderStroke(Color.LIGHTGRAY, BorderStrokeStyle.SOLID, null, new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
this.setBorder(new Border(borderStroke));
}
public void select()
{
BorderStroke borderStroke = new BorderStroke(processStepItem.getColor(), BorderStrokeStyle.SOLID, null,
new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
BorderStroke borderStroke = new BorderStroke(processStepItem.getColor(), BorderStrokeStyle.SOLID, null, new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
this.setBorder(new Border(borderStroke));
setTextFill(processStepItem.getColor());
}

View File

@ -160,7 +160,10 @@ public class WithdrawalController implements Initializable, ChildController, Hib
public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{
BitSquareValidator.resetTextFields(withdrawFromTextField, withdrawToTextField, amountTextField, changeAddressTextField);
if (transaction != null) log.info("onWithdraw onSuccess txid:" + transaction.getHashAsString());
if (transaction != null)
{
log.info("onWithdraw onSuccess txid:" + transaction.getHashAsString());
}
}
@Override

View File

@ -126,9 +126,13 @@ public class WithdrawalListItem
return "Registration fee";
case TRADE:
if (addressEntry.getTradeId() != null)
{
return "Trade ID: " + addressEntry.getTradeId();
}
else
{
return "Trade (not used yet)";
}
case ARBITRATOR_DEPOSIT:
return "Arbitration deposit";
}

View File

@ -50,7 +50,9 @@ public class HomeController implements Initializable, ChildController, Navigatio
public ChildController navigateToView(NavigationItem navigationItem)
{
if (arbitratorRegistrationController != null)
{
arbitratorRegistrationController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try

View File

@ -60,7 +60,9 @@ public class MarketController implements Initializable, NavigationController, Ch
childController.setNavigationController(this);
if (childController instanceof OrderBookController)
{
orderBookController = (OrderBookController) childController;
}
String tabLabel;
switch (navigationItem)
@ -125,7 +127,9 @@ public class MarketController implements Initializable, NavigationController, Ch
{
tabPane.getSelectionModel().select(0);
if (orderBookController != null)
{
orderBookController.setDirection(direction);
}
}
}

View File

@ -63,8 +63,8 @@ public class CreateOfferController implements Initializable, ChildController, Hi
@FXML
private Button placeOfferButton, closeButton;
@FXML
private TextField collateralTextField, minAmountTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField,
acceptedCountriesTextField, acceptedLanguagesTextField, feeLabel, txTextField;
private TextField collateralTextField, minAmountTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField,
acceptedLanguagesTextField, feeLabel, txTextField;
@FXML
private ConfidenceProgressIndicator progressIndicator;
@ -188,18 +188,18 @@ public class CreateOfferController implements Initializable, ChildController, Hi
if (user.getCurrentBankAccount() != null)
{
offer = new Offer(user.getMessagePubKeyAsHex(),
direction,
BitSquareConverter.stringToDouble(priceTextField.getText()),
BtcFormatter.stringValueToSatoshis(amountTextField.getText()),
BtcFormatter.stringValueToSatoshis(minAmountTextField.getText()),
user.getCurrentBankAccount().getBankAccountType(),
user.getCurrentBankAccount().getCurrency(),
user.getCurrentBankAccount().getCountry(),
user.getCurrentBankAccount().getUid(),
arbitrator,
collateral,
settings.getAcceptedCountries(),
settings.getAcceptedLanguageLocales());
direction,
BitSquareConverter.stringToDouble(priceTextField.getText()),
BtcFormatter.stringValueToSatoshis(amountTextField.getText()),
BtcFormatter.stringValueToSatoshis(minAmountTextField.getText()),
user.getCurrentBankAccount().getBankAccountType(),
user.getCurrentBankAccount().getCurrency(),
user.getCurrentBankAccount().getCountry(),
user.getCurrentBankAccount().getUid(),
arbitrator,
collateral,
settings.getAcceptedCountries(),
settings.getAcceptedLanguageLocales());
try

View File

@ -220,7 +220,8 @@ public class OrderBookController implements Initializable, ChildController
}
else
{
Action response = Popups.openErrorPopup("Registration fee not confirmed yet", "The registration fee transaction has not been confirmed yet in the blockchain. Please wait until it has at least 1 confirmation.");
Action response = Popups.openErrorPopup("Registration fee not confirmed yet",
"The registration fee transaction has not been confirmed yet in the blockchain. Please wait until it has at least 1 confirmation.");
if (response == Dialog.Actions.OK)
{
MainController.GET_INSTANCE().navigateToView(NavigationItem.FUNDS);
@ -229,7 +230,8 @@ public class OrderBookController implements Initializable, ChildController
}
else
{
Action response = Popups.openErrorPopup("Missing registration fee", "You have not funded the full registration fee of " + BtcFormatter.formatSatoshis(FeePolicy.ACCOUNT_REGISTRATION_FEE) + " BTC.");
Action response = Popups.openErrorPopup("Missing registration fee",
"You have not funded the full registration fee of " + BtcFormatter.formatSatoshis(FeePolicy.ACCOUNT_REGISTRATION_FEE) + " BTC.");
if (response == Dialog.Actions.OK)
{
MainController.GET_INSTANCE().navigateToView(NavigationItem.FUNDS);
@ -249,10 +251,17 @@ public class OrderBookController implements Initializable, ChildController
if (selectedIndex >= 0)
{
Dialogs.CommandLink settingsCommandLink = new Dialogs.CommandLink("Open settings", "You need to configure your settings before you can actively trade.");
Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds", "You need to pay the registration fee before you can actively trade. That is needed as prevention against fraud.");
Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration", "When settings are configured and the fee deposit is done your registration transaction will be published to the Bitcoin \nnetwork.");
Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds",
"You need to pay the registration fee before you can actively trade. That is needed as prevention against fraud.");
Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration",
"When settings are configured and the fee deposit is done your registration transaction will be published to "
+ "the Bitcoin \nnetwork.");
List<Dialogs.CommandLink> commandLinks = Arrays.asList(settingsCommandLink, depositFeeCommandLink, sendRegistrationCommandLink);
Action registrationMissingAction = Popups.openRegistrationMissingPopup("Not registered yet", "Please follow these steps:", "You need to register before you can place an offer.", commandLinks, selectedIndex);
Action registrationMissingAction = Popups.openRegistrationMissingPopup("Not registered yet",
"Please follow these steps:",
"You need to register before you can place an offer.",
commandLinks,
selectedIndex);
if (registrationMissingAction == settingsCommandLink)
{
MainController.GET_INSTANCE().navigateToView(NavigationItem.SETTINGS);
@ -276,7 +285,10 @@ public class OrderBookController implements Initializable, ChildController
public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{
log.debug("payRegistrationFee onSuccess");
if (transaction != null) log.info("payRegistrationFee onSuccess tx id:" + transaction.getHashAsString());
if (transaction != null)
{
log.info("payRegistrationFee onSuccess tx id:" + transaction.getHashAsString());
}
}
@Override
@ -289,8 +301,13 @@ public class OrderBookController implements Initializable, ChildController
{
walletFacade.payRegistrationFee(user.getStringifiedBankAccounts(), callback);
if (walletFacade.getRegistrationAddressInfo() != null)
{
user.setAccountID(walletFacade.getRegistrationAddressInfo().toString());
if (messageFacade != null && messageFacade.getPubKey() != null) user.setMessagePubKeyAsHex(DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey()));
}
if (messageFacade != null && messageFacade.getPubKey() != null)
{
user.setMessagePubKeyAsHex(DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey()));
}
storage.write(user.getClass().getName(), user);
} catch (InsufficientMoneyException e1)
@ -308,7 +325,9 @@ public class OrderBookController implements Initializable, ChildController
{
ChildController nextController = navigationController.navigateToView(NavigationItem.CREATE_OFFER);
if (nextController != null)
{
((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter);
}
}
else
{
@ -333,12 +352,18 @@ public class OrderBookController implements Initializable, ChildController
BigInteger requestedAmount;
if (!"".equals(amount.getText()))
{
requestedAmount = BtcFormatter.stringValueToSatoshis(amount.getText());
}
else
{
requestedAmount = offer.getAmount();
}
if (takerOfferController != null)
{
takerOfferController.initWithData(offer, requestedAmount);
}
}
else
{
@ -359,16 +384,22 @@ public class OrderBookController implements Initializable, ChildController
orderBookTable.sort();
if (orderBookTable.getItems() != null)
{
createOfferButton.setDefaultButton(orderBookTable.getItems().isEmpty());
}
}
private void setupPolling()
{
pollingTimer = Utilities.setInterval(1000, (animationTimer) -> {
if (user.getCurrentBankAccount() != null)
{
messageFacade.getDirtyFlag(user.getCurrentBankAccount().getCurrency());
}
else
{
messageFacade.getDirtyFlag(CurrencyUtil.getDefaultCurrency());
}
return null;
});

View File

@ -17,8 +17,8 @@ import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.Trading;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocol;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocolListener;
import io.bitsquare.trade.protocol.taker.ProtocolForTakerAsSeller;
import io.bitsquare.trade.protocol.taker.ProtocolForTakerAsSellerListener;
import java.math.BigInteger;
import java.net.URL;
import java.util.ResourceBundle;
@ -53,9 +53,9 @@ public class TakerOfferController implements Initializable, ChildController
@FXML
private ValidatedTextField amountTextField;
@FXML
private TextField priceTextField, volumeTextField, collateralTextField, feeTextField, totalTextField, bankAccountTypeTextField, countryTextField,
arbitratorsTextField, supportedLanguagesTextField, supportedCountriesTextField, depositTxIdTextField, summaryPaidTextField, summaryReceivedTextField, summaryFeesTextField,
summaryCollateralTextField, summaryDepositTxIdTextField, summaryPayoutTxIdTextField;
private TextField priceTextField, volumeTextField, collateralTextField, feeTextField, totalTextField, bankAccountTypeTextField, countryTextField, arbitratorsTextField,
supportedLanguagesTextField, supportedCountriesTextField, depositTxIdTextField, summaryPaidTextField, summaryReceivedTextField, summaryFeesTextField, summaryCollateralTextField,
summaryDepositTxIdTextField, summaryPayoutTxIdTextField;
@FXML
private Label infoLabel, headLineLabel;
@FXML
@ -84,7 +84,9 @@ public class TakerOfferController implements Initializable, ChildController
this.requestedAmount = requestedAmount.compareTo(BigInteger.ZERO) == 0 ? offer.getAmount() : requestedAmount;
if (amountTextField != null)
{
applyData();
}
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -172,68 +174,67 @@ public class TakerOfferController implements Initializable, ChildController
{
takeOfferButton.setDisable(true);
amountTextField.setEditable(false);
trading.takeOffer(amount, offer, new TakerAsSellerProtocolListener()
{
@Override
public void onDepositTxPublished(String depositTxId)
{
setDepositTxId(depositTxId);
accordion.setExpandedPane(waitBankTxTitledPane);
infoLabel.setText("Deposit transaction published by offerer.\n" +
"As soon as the offerer starts the \n" +
"Bank transfer, you will get informed.");
depositTxIdTextField.setText(depositTxId);
}
trading.takeOffer(amount, offer, new ProtocolForTakerAsSellerListener()
{
@Override
public void onDepositTxPublished(String depositTxId)
{
setDepositTxId(depositTxId);
accordion.setExpandedPane(waitBankTxTitledPane);
infoLabel.setText("Deposit transaction published by offerer.\n" +
"As soon as the offerer starts the \n" +
"Bank transfer, you will get informed.");
depositTxIdTextField.setText(depositTxId);
}
@Override
public void onBankTransferInited(String tradeId)
{
setTradeId(tradeId);
headLineLabel.setText("Bank transfer inited");
infoLabel.setText("Check your bank account and continue \n" +
"when you have received the money.");
receivedFiatButton.setDisable(false);
}
@Override
public void onBankTransferInited(String tradeId)
{
setTradeId(tradeId);
headLineLabel.setText("Bank transfer inited");
infoLabel.setText("Check your bank account and continue \n" + "when you have received the money.");
receivedFiatButton.setDisable(false);
}
@Override
public void onPayoutTxPublished(Trade trade, String payoutTxId)
{
accordion.setExpandedPane(summaryTitledPane);
summaryPaidTextField.setText(BtcFormatter.formatSatoshis(trade.getTradeAmount()));
summaryReceivedTextField.setText(BitSquareFormatter.formatVolume(trade.getOffer().getPrice() * BtcFormatter.satoshiToBTC(trade.getTradeAmount())));
summaryFeesTextField.setText(BtcFormatter.formatSatoshis(FeePolicy.TAKE_OFFER_FEE.add(FeePolicy.TX_FEE)));
summaryCollateralTextField.setText(BtcFormatter.formatSatoshis(trade.getCollateralAmount()));
summaryDepositTxIdTextField.setText(depositTxId);
summaryPayoutTxIdTextField.setText(payoutTxId);
}
@Override
public void onPayoutTxPublished(Trade trade, String payoutTxId)
{
accordion.setExpandedPane(summaryTitledPane);
summaryPaidTextField.setText(BtcFormatter.formatSatoshis(trade.getTradeAmount()));
summaryReceivedTextField.setText(BitSquareFormatter.formatVolume(trade.getOffer().getPrice() * BtcFormatter.satoshiToBTC(trade.getTradeAmount())));
summaryFeesTextField.setText(BtcFormatter.formatSatoshis(FeePolicy.TAKE_OFFER_FEE.add(FeePolicy.TX_FEE)));
summaryCollateralTextField.setText(BtcFormatter.formatSatoshis(trade.getCollateralAmount()));
summaryDepositTxIdTextField.setText(depositTxId);
summaryPayoutTxIdTextField.setText(payoutTxId);
}
@Override
public void onFault(Throwable throwable, TakerAsSellerProtocol.State state)
{
log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable);
}
@Override
public void onFault(Throwable throwable, ProtocolForTakerAsSeller.State state)
{
log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable);
}
@Override
public void onWaitingForPeerResponse(TakerAsSellerProtocol.State state)
{
log.debug("Waiting for peers response at state " + state);
}
@Override
public void onWaitingForPeerResponse(ProtocolForTakerAsSeller.State state)
{
log.debug("Waiting for peers response at state " + state);
}
@Override
public void onCompleted(TakerAsSellerProtocol.State state)
{
log.debug("Trade protocol completed at state " + state);
}
@Override
public void onCompleted(ProtocolForTakerAsSeller.State state)
{
log.debug("Trade protocol completed at state " + state);
}
@Override
public void onTakeOfferRequestRejected(Trade trade)
{
log.error("Take offer request rejected");
Popups.openErrorPopup("Take offer request rejected", "Your take offer request has been rejected. It might be that the offerer got another request shortly before your request arrived.");
}
}
);
@Override
public void onTakeOfferRequestRejected(Trade trade)
{
log.error("Take offer request rejected");
Popups.openErrorPopup("Take offer request rejected",
"Your take offer request has been rejected. It might be that the offerer got another request shortly before your request arrived.");
}
});
}
}

View File

@ -196,7 +196,9 @@ public class TakerTradeController implements Initializable, ChildController
try
{
if (offer.getArbitrator() != null && offer.getArbitrator().getWebUrl() != null)
{
Utilities.openURL(offer.getArbitrator().getWebUrl());
}
} catch (Exception e1)
{
log.warn(e1.toString());
@ -230,13 +232,13 @@ public class TakerTradeController implements Initializable, ChildController
trade = trading.createTrade(offer);
trade.setTradeAmount(BtcFormatter.stringValueToSatoshis(amountTextField.getText()));
/* if (!blockChainFacade.verifyAccountRegistration(offer.getAccountId()))
/* if (!blockChainFacade.verifyAccountRegistration(offer.getTakerAccountId()))
{
Popups.openErrorPopup("Offerers account ID not valid", "Offerers registration tx is not found in blockchain or does not match the requirements.");
return;
}
if (blockChainFacade.isAccountIDBlacklisted(offer.getAccountId()))
if (blockChainFacade.isAccountIDBlacklisted(offer.getTakerAccountId()))
{
Popups.openErrorPopup("Offerers account ID is blacklisted", "Offerers account ID is blacklisted.");
return;

View File

@ -155,7 +155,9 @@ public class PendingTradeController implements Initializable, ChildController, H
trading.getNewTradeProperty().addListener((observableValue, oldTradeId, newTradeId) -> {
Trade newTrade = trading.getTrade(newTradeId);
if (newTrade != null)
{
tradeItems.add(new PendingTradesListItem(newTrade));
}
});
initCopyIcons();
@ -163,7 +165,9 @@ public class PendingTradeController implements Initializable, ChildController, H
// select
Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) -> e.getTrade().getId().equals(trading.getPendingTrade().getId())).findFirst();
if (currentTradeItemOptional.isPresent())
{
openTradesTable.getSelectionModel().select(currentTradeItemOptional.get());
}
tradeItems.addListener((ListChangeListener<PendingTradesListItem>) change -> {
if (openTradesTable.getSelectionModel().getSelectedItem() == null && tradeItems.size() > 0)

View File

@ -22,12 +22,7 @@ public class Popups
public static void openInformationPopup(String title, String message, String masthead)
{
Dialogs.create()
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showInformation();
Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showInformation();
}
// Confirm
@ -41,13 +36,7 @@ public class Popups
List<Action> actions = new ArrayList<>();
actions.add(Dialog.Actions.OK);
actions.add(Dialog.Actions.CANCEL);
return Dialogs.create()
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.actions(actions)
.showConfirm();
return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).actions(actions).showConfirm();
}
// Warning
@ -63,12 +52,7 @@ public class Popups
public static void openWarningPopup(String title, String message, String masthead)
{
Dialogs.create()
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showWarning();
Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showWarning();
}
// Error
@ -84,12 +68,7 @@ public class Popups
public static Action openErrorPopup(String title, String message, String masthead)
{
return Dialogs.create()
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showError();
return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showError();
}
// Exception
@ -105,12 +84,7 @@ public class Popups
public static Action openExceptionPopup(Throwable throwable, String title, String message, String masthead)
{
return Dialogs.create()
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showException(throwable);
return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showException(throwable);
}
// Support handling of uncaught exception from any thread (also non gui thread)
@ -120,26 +94,36 @@ public class Popups
// while dev
throwable.printStackTrace();
Runnable runnable = () ->
{
Runnable runnable = () -> {
if (Throwables.getRootCause(throwable) instanceof BlockStoreException)
{
Action response = Popups.openErrorPopup("Application already running", "This application is already running and cannot be started twice.", "");
if (response == Dialog.Actions.OK)
{
Platform.exit();
}
}
else
{
Action response = Popups.openExceptionPopup(throwable, "Exception", "", "A critical error has occurred.\nPlease copy the exception details and send a bug report to bugs@bitsquare.io.");
Action response = Popups.openExceptionPopup(throwable,
"Exception",
"",
"A critical error has occurred.\nPlease copy the exception details and send a bug report to bugs@bitsquare.io.");
if (response == Dialog.Actions.OK)
{
Platform.exit();
}
}
};
if (Platform.isFxApplicationThread())
{
runnable.run();
}
else
{
Platform.runLater(runnable);
}
}
@ -152,11 +136,6 @@ public class Popups
public static Action openRegistrationMissingPopup(String title, String message, String masthead, List<Dialogs.CommandLink> commandLinks, int selectedIndex)
{
return Dialogs.create()
.owner(BitSquare.getStage())
.title(title)
.message(message)
.masthead(masthead)
.showCommandLinks(commandLinks.get(selectedIndex), commandLinks);
return Dialogs.create().owner(BitSquare.getStage()).title(title).message(message).masthead(masthead).showCommandLinks(commandLinks.get(selectedIndex), commandLinks);
}
}

View File

@ -149,21 +149,20 @@ public class SettingsController implements Initializable, ChildController, Navig
idVerifications.add(Arbitrator.ID_VERIFICATION.GOV_ID);
Arbitrator arbitrator = new Arbitrator(pubKeyAsHex,
messagePubKeyAsHex,
"Manfred Karrer",
Arbitrator.ID_TYPE.REAL_LIFE_ID,
languages,
new Reputation(),
1,
0.01,
0.001,
10,
0.1,
arbitrationMethods,
idVerifications,
"http://bitsquare.io/",
"Bla bla..."
);
messagePubKeyAsHex,
"Manfred Karrer",
Arbitrator.ID_TYPE.REAL_LIFE_ID,
languages,
new Reputation(),
1,
0.01,
0.001,
10,
0.1,
arbitrationMethods,
idVerifications,
"http://bitsquare.io/",
"Bla bla...");
arbitratorList.add(arbitrator);
settings.addAcceptedArbitrator(arbitrator);
@ -207,7 +206,9 @@ public class SettingsController implements Initializable, ChildController, Navig
{
if (childController != null)
{
childController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try
@ -231,7 +232,9 @@ public class SettingsController implements Initializable, ChildController, Navig
stage.setScene(scene);
stage.setOnHidden(windowEvent -> {
if (navigationItem == NavigationItem.ARBITRATOR_OVERVIEW)
{
updateArbitrators();
}
});
stage.show();
@ -351,52 +354,51 @@ public class SettingsController implements Initializable, ChildController, Navig
private void initLanguage()
{
languagesListView.setCellFactory(new Callback<ListView<Locale>, ListCell<Locale>>()
{
{
@Override
public ListCell<Locale> call(ListView<Locale> list)
{
return new ListCell<Locale>()
{
final HBox hBox = new HBox();
final Label label = new Label();
final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE);
@Override
public ListCell<Locale> call(ListView<Locale> list)
{
return new ListCell<Locale>()
{
final HBox hBox = new HBox();
final Label label = new Label();
final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE);
{
label.setPrefWidth(565);
{
label.setPrefWidth(565);
icon.setMouseTransparent(true);
icon.setMouseTransparent(true);
removeButton.setGraphic(icon);
removeButton.setId("icon-button");
removeButton.setGraphic(icon);
removeButton.setId("icon-button");
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(label, removeButton);
}
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(label, removeButton);
}
@Override
public void updateItem(final Locale item, boolean empty)
{
super.updateItem(item, empty);
if (item != null && !empty)
{
label.setText(item.getDisplayName());
@Override
public void updateItem(final Locale item, boolean empty)
{
super.updateItem(item, empty);
if (item != null && !empty)
{
label.setText(item.getDisplayName());
removeButton.setOnAction(actionEvent -> removeLanguage(item));
removeButton.setOnAction(actionEvent -> removeLanguage(item));
setGraphic(hBox);
}
else
{
setGraphic(null);
}
}
};
}
}
);
setGraphic(hBox);
}
else
{
setGraphic(null);
}
}
};
}
});
languagesListView.setItems(languageList);
languageComboBox.setItems(FXCollections.observableArrayList(LanguageUtil.getAllLanguageLocales()));
@ -437,53 +439,52 @@ public class SettingsController implements Initializable, ChildController, Navig
});
countriesListView.setCellFactory(new Callback<ListView<Country>, ListCell<Country>>()
{
{
@Override
public ListCell<Country> call(ListView<Country> list)
{
return new ListCell<Country>()
{
final HBox hBox = new HBox();
final Label label = new Label();
final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE);
@Override
public ListCell<Country> call(ListView<Country> list)
{
return new ListCell<Country>()
{
final HBox hBox = new HBox();
final Label label = new Label();
final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE);
{
label.setPrefWidth(565);
{
label.setPrefWidth(565);
icon.setMouseTransparent(true);
icon.setMouseTransparent(true);
removeButton.setGraphic(icon);
removeButton.setId("icon-button");
removeButton.setGraphic(icon);
removeButton.setId("icon-button");
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(label, removeButton);
}
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(label, removeButton);
}
@Override
public void updateItem(final Country item, boolean empty)
{
super.updateItem(item, empty);
if (item != null && !empty)
{
label.setText(item.getName());
@Override
public void updateItem(final Country item, boolean empty)
{
super.updateItem(item, empty);
if (item != null && !empty)
{
label.setText(item.getName());
removeButton.setOnAction(actionEvent -> removeCountry(item));
removeButton.setOnAction(actionEvent -> removeCountry(item));
setGraphic(hBox);
}
else
{
setGraphic(null);
}
}
};
}
}
);
setGraphic(hBox);
}
else
{
setGraphic(null);
}
}
};
}
});
countriesListView.setItems(countryList);
countryComboBox.setConverter(new StringConverter<Country>()
@ -508,53 +509,52 @@ public class SettingsController implements Initializable, ChildController, Navig
private void initArbitrators()
{
arbitratorsListView.setCellFactory(new Callback<ListView<Arbitrator>, ListCell<Arbitrator>>()
{
{
@Override
public ListCell<Arbitrator> call(ListView<Arbitrator> list)
{
return new ListCell<Arbitrator>()
{
final HBox hBox = new HBox();
final Label label = new Label();
final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE);
@Override
public ListCell<Arbitrator> call(ListView<Arbitrator> list)
{
return new ListCell<Arbitrator>()
{
final HBox hBox = new HBox();
final Label label = new Label();
final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE);
{
label.setPrefWidth(565);
{
label.setPrefWidth(565);
icon.setMouseTransparent(true);
icon.setMouseTransparent(true);
removeButton.setGraphic(icon);
removeButton.setId("icon-button");
removeButton.setGraphic(icon);
removeButton.setId("icon-button");
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(label, removeButton);
}
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.getChildren().addAll(label, removeButton);
}
@Override
public void updateItem(final Arbitrator item, boolean empty)
{
super.updateItem(item, empty);
if (item != null && !empty)
{
label.setText(item.getName());
@Override
public void updateItem(final Arbitrator item, boolean empty)
{
super.updateItem(item, empty);
if (item != null && !empty)
{
label.setText(item.getName());
removeButton.setOnAction(actionEvent -> removeArbitrator(item));
removeButton.setOnAction(actionEvent -> removeArbitrator(item));
setGraphic(hBox);
}
else
{
setGraphic(null);
}
}
};
}
}
);
setGraphic(hBox);
}
else
{
setGraphic(null);
}
}
};
}
});
arbitratorsListView.setItems(arbitratorList);
}
@ -645,7 +645,9 @@ public class SettingsController implements Initializable, ChildController, Navig
bankAccountPrimaryIDTextField.setText("dummy");
bankAccountSecondaryIDTextField.setText("dummy");
if (user.getCurrentBankAccount() == null)
{
onSaveBankAccount();
}
}
private void resetBankAccountInput()
@ -809,14 +811,13 @@ public class SettingsController implements Initializable, ChildController, Navig
{
if (verifyBankAccountData())
{
BankAccount bankAccount = new BankAccount(
bankAccountTypesComboBox.getSelectionModel().getSelectedItem(),
bankAccountCurrencyComboBox.getSelectionModel().getSelectedItem(),
bankAccountCountryComboBox.getSelectionModel().getSelectedItem(),
bankAccountTitleTextField.getText(),
bankAccountHolderNameTextField.getText(),
bankAccountPrimaryIDTextField.getText(),
bankAccountSecondaryIDTextField.getText());
BankAccount bankAccount = new BankAccount(bankAccountTypesComboBox.getSelectionModel().getSelectedItem(),
bankAccountCurrencyComboBox.getSelectionModel().getSelectedItem(),
bankAccountCountryComboBox.getSelectionModel().getSelectedItem(),
bankAccountTitleTextField.getText(),
bankAccountHolderNameTextField.getText(),
bankAccountPrimaryIDTextField.getText(),
bankAccountSecondaryIDTextField.getText());
user.addBankAccount(bankAccount);
saveUser();
@ -844,9 +845,10 @@ public class SettingsController implements Initializable, ChildController, Navig
BitSquareValidator.textFieldBankAccountPrimaryIDIsValid(bankAccountPrimaryIDTextField, bankAccountTypeInfo);
BitSquareValidator.textFieldBankAccountSecondaryIDIsValid(bankAccountSecondaryIDTextField, bankAccountTypeInfo);
return bankAccountTypesComboBox.getSelectionModel().getSelectedItem() != null
&& bankAccountCountryComboBox.getSelectionModel().getSelectedItem() != null
&& bankAccountCurrencyComboBox.getSelectionModel().getSelectedItem() != null;
return bankAccountTypesComboBox.getSelectionModel().getSelectedItem() != null && bankAccountCountryComboBox.getSelectionModel()
.getSelectedItem() != null && bankAccountCurrencyComboBox.getSelectionModel()
.getSelectedItem() !=
null;
} catch (BitSquareValidator.ValidationException e)
{
return false;

View File

@ -50,9 +50,13 @@ public class BitSquareFormatter
public static String formatAmountWithMinAmount(double amount, double minAmount, boolean useBTC)
{
if (useBTC)
{
return formatDouble(amount) + " BTC (" + formatDouble(minAmount) + " BTC)";
}
else
{
return formatDouble(amount) + " (" + formatDouble(minAmount) + ")";
}
}
@ -95,7 +99,9 @@ public class BitSquareFormatter
{
String result = (direction == Direction.BUY) ? "Buy" : "Sell";
if (allUpperCase)
{
result = result.toUpperCase();
}
return result;
}
@ -143,7 +149,9 @@ public class BitSquareFormatter
result += country.getName();
i++;
if (i < countries.size())
{
result += ", ";
}
}
return result;
}
@ -157,7 +165,9 @@ public class BitSquareFormatter
result += locale.getDisplayLanguage();
i++;
if (i < languageLocales.size())
{
result += ", ";
}
}
return result;
}
@ -172,7 +182,9 @@ public class BitSquareFormatter
result += Localisation.get(item.toString());
i++;
if (i < items.size())
{
result += ", ";
}
}
return result;
}
@ -187,7 +199,9 @@ public class BitSquareFormatter
result += Localisation.get(item.toString());
i++;
if (i < items.size())
{
result += ", ";
}
}
return result;
}

View File

@ -107,7 +107,9 @@ public class ConfidenceDisplay
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{
if (tx.getHashAsString().equals(transaction.getHashAsString()))
{
updateBalance(newBalance);
}
// log.debug("onCoinsReceived " + newBalance);
}
@ -115,7 +117,9 @@ public class ConfidenceDisplay
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{
if (tx.getHashAsString().equals(transaction.getHashAsString()))
{
updateConfidence(transaction);
}
// log.debug("onTransactionConfidenceChanged newTransaction " + newTransaction.getHashAsString());
}
@ -123,7 +127,9 @@ public class ConfidenceDisplay
public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{
if (tx.getHashAsString().equals(transaction.getHashAsString()))
{
updateBalance(newBalance);
}
}
@Override
@ -155,7 +161,9 @@ public class ConfidenceDisplay
progressIndicator.setProgress(0);
confirmationLabel.setText("");
if (balanceTextField != null)
{
balanceTextField.setText("");
}
}
private void updateBalance(BigInteger balance)
@ -183,11 +191,15 @@ public class ConfidenceDisplay
}
}
if (latestTransaction != null && (transaction == null || latestTransaction.getHashAsString().equals(transaction.getHashAsString())))
{
updateConfidence(latestTransaction);
}
}
if (balanceTextField != null)
{
balanceTextField.setText(BtcFormatter.formatSatoshis(balance));
}
}
private void updateConfidence(Transaction tx)

View File

@ -29,9 +29,13 @@ public class Country implements Serializable
public boolean equals(Object obj)
{
if (!(obj instanceof Country))
{
return false;
}
if (obj == this)
{
return true;
}
final Country other = (Country) obj;
return code.equals(other.getCode());

View File

@ -7,211 +7,17 @@ import java.util.stream.Collectors;
public class CountryUtil
{
private static final String[] countryCodes = new String[]{"AE",
"AL",
"AR",
"AT",
"AU",
"BA",
"BE",
"BG",
"BH",
"BO",
"BR",
"BY",
"CA",
"CH",
"CL",
"CN",
"CO",
"CR",
"CS",
"CU",
"CY",
"CZ",
"DE",
"DK",
"DO",
"DZ",
"EC",
"EE",
"EG",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HR",
"HU",
"ID",
"IE",
"IL",
"IN",
"IQ",
"IS",
"IT",
"JO",
"JP",
"KR",
"KW",
"LB",
"LT",
"LU",
"LV",
"LY",
"MA",
"ME",
"MK",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"OM",
"PA",
"PE",
"PH",
"PL",
"PR",
"PT",
"PY",
"QA",
"RO",
"RS",
"RU",
"SA",
"SD",
"SE",
"SG",
"SI",
"SK",
"SV",
"SY",
"TH",
"TN",
"TR",
"TW",
"UA",
"US",
"UY",
"VE",
"VN",
"YE",
"ZA"
};
private static final String[] countryCodes = new String[]{"AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH", "BO", "BR", "BY", "CA", "CH", "CL", "CN", "CO", "CR", "CS", "CU", "CY", "CZ",
"DE", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JO", "JP", "KR", "KW", "LB", "LT", "LU",
"LV", "LY", "MA", "ME", "MK", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PR", "PT", "PY", "QA", "RO", "RS", "RU", "SA", "SD", "SE", "SG", "SI", "SK", "SV",
"SY", "TH", "TN", "TR", "TW", "UA", "US", "UY", "VE", "VN", "YE", "ZA"};
private static final List<String> countryCodeList = Arrays.asList(countryCodes);
private static final String[] regionCodes = new String[]{
"AS",
"EU",
"SA",
"EU",
"OC",
"EU",
"EU",
"EU",
"AS",
"SA",
"SA",
"EU",
"NA",
"EU",
"SA",
"AS",
"SA",
"NA",
"EU",
"NA",
"AS",
"EU",
"EU",
"EU",
"NA",
"AF",
"SA",
"EU",
"AF",
"EU",
"EU",
"EU",
"EU",
"EU",
"NA",
"AS",
"NA",
"EU",
"EU",
"AS",
"EU",
"AS",
"AS",
"AS",
"EU",
"EU",
"AS",
"AS",
"AS",
"AS",
"AS",
"EU",
"EU",
"EU",
"AF",
"AF",
"EU",
"EU",
"EU",
"NA",
"AS",
"NA",
"EU",
"EU",
"OC",
"AS",
"NA",
"SA",
"AS",
"EU",
"NA",
"EU",
"SA",
"AS",
"EU",
"EU",
"EU",
"AS",
"AF",
"EU",
"AS",
"EU",
"EU",
"NA",
"AS",
"AS",
"AF",
"AS",
"AS",
"EU",
"NA",
"SA",
"SA",
"AS",
"AS",
"AF"
};
private static final String[] regionCodes = new String[]{"AS", "EU", "SA", "EU", "OC", "EU", "EU", "EU", "AS", "SA", "SA", "EU", "NA", "EU", "SA", "AS", "SA", "NA", "EU", "NA", "AS", "EU",
"EU", "EU", "NA", "AF", "SA", "EU", "AF", "EU", "EU", "EU", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "AS", "EU", "AS", "AS", "AS", "EU", "EU", "AS", "AS", "AS", "AS", "AS", "EU", "EU",
"EU", "AF", "AF", "EU", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "OC", "AS", "NA", "SA", "AS", "EU", "NA", "EU", "SA", "AS", "EU", "EU", "EU", "AS", "AF", "EU", "AS", "EU", "EU", "NA",
"AS", "AS", "AF", "AS", "AS", "EU", "NA", "SA", "SA", "AS", "AS", "AF"};
private static final List<String> regionCodeList = Arrays.asList(regionCodes);
private static final String[][] regionCodeToName = new String[][]{
{"NA", "North America"},
{"SA", "South America"},
{"AF", "Africa"},
{"EU", "Europe"},
{"AS", "Asia"},
{"OC", "Oceania"}
};
private static final String[][] regionCodeToName = new String[][]{{"NA", "North America"}, {"SA", "South America"}, {"AF", "Africa"}, {"EU", "Europe"}, {"AS", "Asia"}, {"OC", "Oceania"}};
public static List<Region> getAllRegions()
@ -279,7 +85,9 @@ public class CountryUtil
for (final String[] regionName : regionCodeToName)
{
if (regionName[0].equals(regionCode))
{
return regionName[1];
}
}
return regionCode;
}
@ -310,9 +118,13 @@ public class CountryUtil
private static String getRegionCode(String countryCode)
{
if (!countryCode.isEmpty() && countryCodeList.contains(countryCode))
{
return regionCodeList.get(countryCodeList.indexOf(countryCode));
}
else
{
return "Undefined";
}
}
}

View File

@ -26,9 +26,13 @@ public class Region implements Serializable
public boolean equals(Object obj)
{
if (!(obj instanceof Region))
{
return false;
}
if (obj == this)
{
return true;
}
Region other = (Region) obj;
return code.equals(other.getCode());

View File

@ -72,9 +72,13 @@ public class MessageFacade
{
int port = Bindings.MAX_PORT - Math.abs(new Random().nextInt()) % (Bindings.MAX_PORT - Bindings.MIN_DYN_PORT);
if (BitSquare.ID.contains("taker"))
{
port = 4501;
}
else if (BitSquare.ID.contains("offerer"))
{
port = 4500;
}
try
{
@ -93,7 +97,9 @@ public class MessageFacade
public void shutDown()
{
if (myPeer != null)
{
myPeer.shutdown();
}
}
@ -219,17 +225,20 @@ public class MessageFacade
final PeerConnection peerConnection = myPeer.createPeerConnection(peerAddress, 10);
final FutureResponse sendFuture = myPeer.sendDirect(peerConnection).setObject(tradeMessage).start();
sendFuture.addListener(new BaseFutureAdapter<BaseFuture>()
{
@Override
public void operationComplete(BaseFuture baseFuture) throws Exception
{
if (sendFuture.isSuccess())
Platform.runLater(() -> listener.onResult());
else
Platform.runLater(() -> listener.onFailed());
}
}
);
{
@Override
public void operationComplete(BaseFuture baseFuture) throws Exception
{
if (sendFuture.isSuccess())
{
Platform.runLater(() -> listener.onResult());
}
else
{
Platform.runLater(() -> listener.onFailed());
}
}
});
}
@ -319,7 +328,9 @@ public class MessageFacade
private void onArbitratorsReceived(Map<Number160, Data> dataMap, boolean success)
{
for (ArbitratorListener arbitratorListener : arbitratorListeners)
{
arbitratorListener.onArbitratorsReceived(dataMap, success);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -346,7 +357,9 @@ public class MessageFacade
{
Object object = data.getObject();
if (object instanceof Long)
{
Platform.runLater(() -> onGetDirtyFlag((Long) object));
}
}
}
@ -366,9 +379,13 @@ public class MessageFacade
isDirty.setValue(!isDirty.get());
}
if (lastTimeStamp > 0)
{
lastTimeStamp = timeStamp;
}
else
{
lastTimeStamp++;
}
}
private Number160 getDirtyLocationKey(Number160 locationKey)
@ -634,9 +651,13 @@ public class MessageFacade
{
myPeer.setObjectDataReply((sender, request) -> {
if (!sender.equals(myPeer.getPeerAddress()))
{
Platform.runLater(() -> onMessage(request, sender));
}
else
{
log.error("Received msg from myself. That should never happen.");
}
//noinspection ReturnOfNull
return null;
});

View File

@ -51,7 +51,9 @@ public class Settings implements Serializable
public void addAcceptedLanguageLocale(Locale locale)
{
if (!acceptedLanguageLocales.contains(locale))
{
acceptedLanguageLocales.add(locale);
}
}
public void removeAcceptedLanguageLocale(Locale item)
@ -62,7 +64,9 @@ public class Settings implements Serializable
public void addAcceptedCountry(Country locale)
{
if (!acceptedCountryLocales.contains(locale))
{
acceptedCountryLocales.add(locale);
}
}
public void removeAcceptedCountry(Country item)
@ -73,7 +77,9 @@ public class Settings implements Serializable
public void addAcceptedArbitrator(Arbitrator arbitrator)
{
if (!acceptedArbitrators.contains(arbitrator))
{
acceptedArbitrators.add(arbitrator);
}
}
public void removeAcceptedArbitrator(Arbitrator item)

View File

@ -237,9 +237,13 @@ public class Storage
// Work around an issue on Windows whereby you can't rename over existing files.
final File canonical = storageFile.getCanonicalFile();
if (canonical.exists() && !canonical.delete())
{
throw new IOException("Failed to delete canonical file for replacement with save");
}
if (!tempFile.renameTo(canonical))
{
throw new IOException("Failed to rename " + tempFile + " to " + canonical);
}
}
else if (!tempFile.renameTo(storageFile))
{
@ -255,7 +259,9 @@ public class Storage
{
log.warn("Temp file still exists after failed save.");
if (!tempFile.delete())
{
log.warn("Cannot delete temp file.");
}
}
}
} catch (IOException e)

View File

@ -12,15 +12,8 @@ import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.TradeMessage;
import io.bitsquare.msg.listeners.TakeOfferRequestListener;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.messages.offerer.*;
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.messages.taker.RequestTakeOfferMessage;
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocol;
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocolListener;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocol;
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocolListener;
import io.bitsquare.trade.protocol.offerer.*;
import io.bitsquare.trade.protocol.taker.*;
import io.bitsquare.user.User;
import java.io.IOException;
import java.math.BigInteger;
@ -49,8 +42,10 @@ public class Trading
private final CryptoFacade cryptoFacade;
private final List<TakeOfferRequestListener> takeOfferRequestListeners = new ArrayList<>();
private final Map<String, TakerAsSellerProtocol> takerAsSellerProtocolMap = new HashMap<>();
private final Map<String, OffererAsBuyerProtocol> offererAsBuyerProtocolMap = new HashMap<>();
//TODO store TakerAsSellerProtocol in trade
private final Map<String, ProtocolForTakerAsSeller> takerAsSellerProtocolMap = new HashMap<>();
private final Map<String, ProtocolForOffererAsBuyer> offererAsBuyerProtocolMap = new HashMap<>();
private final StringProperty newTradeProperty = new SimpleStringProperty();
@ -65,12 +60,7 @@ public class Trading
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public Trading(User user,
Storage storage,
MessageFacade messageFacade,
BlockChainFacade blockChainFacade,
WalletFacade walletFacade,
CryptoFacade cryptoFacade)
public Trading(User user, Storage storage, MessageFacade messageFacade, BlockChainFacade blockChainFacade, WalletFacade walletFacade, CryptoFacade cryptoFacade)
{
this.user = user;
this.storage = storage;
@ -81,15 +71,23 @@ public class Trading
Object offersObject = storage.read(storageKey + ".offers");
if (offersObject instanceof HashMap)
{
offers = (Map<String, Offer>) offersObject;
}
else
{
offers = new HashMap<>();
}
Object tradesObject = storage.read(storageKey + ".trades");
if (tradesObject instanceof HashMap)
{
trades = (Map<String, Trade>) tradesObject;
}
else
{
trades = new HashMap<>();
}
messageFacade.addIncomingTradeMessageListener(this::onIncomingTradeMessage);
}
@ -127,7 +125,9 @@ public class Trading
public void addOffer(Offer offer) throws IOException
{
if (offers.containsKey(offer.getId()))
{
throw new IllegalStateException("offers contains already an offer with the ID " + offer.getId());
}
offers.put(offer.getId(), offer);
saveOffers();
@ -138,7 +138,9 @@ public class Trading
public void removeOffer(Offer offer)
{
if (!offers.containsKey(offer.getId()))
{
throw new IllegalStateException("offers does not contain the offer with the ID " + offer.getId());
}
offers.remove(offer.getId());
saveOffers();
@ -146,14 +148,14 @@ public class Trading
messageFacade.removeOffer(offer);
}
public Trade takeOffer(BigInteger amount, Offer offer, TakerAsSellerProtocolListener listener)
public Trade takeOffer(BigInteger amount, Offer offer, ProtocolForTakerAsSellerListener listener)
{
Trade trade = createTrade(offer);
trade.setTradeAmount(amount);
TakerAsSellerProtocol takerAsSellerProtocol = new TakerAsSellerProtocol(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
takerAsSellerProtocolMap.put(trade.getId(), takerAsSellerProtocol);
takerAsSellerProtocol.start();
ProtocolForTakerAsSeller protocolForTakerAsSeller = new ProtocolForTakerAsSeller(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
takerAsSellerProtocolMap.put(trade.getId(), protocolForTakerAsSeller);
protocolForTakerAsSeller.start();
return trade;
}
@ -166,7 +168,9 @@ public class Trading
public Trade createTrade(Offer offer)
{
if (trades.containsKey(offer.getId()))
{
throw new IllegalStateException("trades contains already an trade with the ID " + offer.getId());
}
Trade trade = new Trade(offer);
trades.put(offer.getId(), trade);
@ -181,7 +185,9 @@ public class Trading
public void removeTrade(Trade trade)
{
if (!trades.containsKey(trade.getId()))
{
throw new IllegalStateException("trades does not contain the trade with the ID " + trade.getId());
}
trades.remove(trade.getId());
saveTrades();
@ -205,70 +211,90 @@ public class Trading
Trade trade = createTrade(offer);
pendingTrade = trade;
OffererAsBuyerProtocol offererAsBuyerProtocol = new OffererAsBuyerProtocol(trade, sender, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user, new OffererAsBuyerProtocolListener()
ProtocolForOffererAsBuyer protocolForOffererAsBuyer = new ProtocolForOffererAsBuyer(trade,
sender,
messageFacade,
walletFacade,
blockChainFacade,
cryptoFacade,
user,
new ProtocolForOffererAsBuyerListener()
{
@Override
public void onOfferAccepted(Offer offer)
{
removeOffer(offer);
}
@Override
public void onDepositTxPublished(String depositTxID)
{
log.trace("trading onDepositTxPublishedMessage " + depositTxID);
}
@Override
public void onDepositTxConfirmedUpdate(TransactionConfidence confidence)
{
log.trace("trading onDepositTxConfirmedUpdate");
}
@Override
public void onPayoutTxPublished(String payoutTxAsHex)
{
Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(),
Utils.parseAsHexOrBase58(payoutTxAsHex));
trade.setPayoutTransaction(payoutTx);
trade.setState(Trade.State.COMPLETED);
log.debug("trading onPayoutTxPublishedMessage");
}
@Override
public void onFault(Throwable throwable, ProtocolForOffererAsBuyer.State state)
{
log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process",
"Error while executing trade process at state: " + state + " / " +
throwable);
}
@Override
public void onWaitingForPeerResponse(ProtocolForOffererAsBuyer.State state)
{
log.debug("Waiting for peers response at state " + state);
}
@Override
public void onCompleted(ProtocolForOffererAsBuyer.State state)
{
log.debug("Trade protocol completed at state " + state);
}
@Override
public void onWaitingForUserInteraction(ProtocolForOffererAsBuyer.State state)
{
log.debug("Waiting for UI activity at state " + state);
}
@Override
public void onDepositTxConfirmedInBlockchain()
{
log.trace("trading onDepositTxConfirmedInBlockchain");
}
});
if (!offererAsBuyerProtocolMap.containsKey(trade.getId()))
{
@Override
public void onOfferAccepted(Offer offer)
{
removeOffer(offer);
}
offererAsBuyerProtocolMap.put(trade.getId(), protocolForOffererAsBuyer);
}
else
{
// We don't store the protocol in case we have already a pending offer. The protocol is only temporary used to reply with a reject message.
log.trace("offererAsBuyerProtocol not stored as offer is already pending.");
}
@Override
public void onDepositTxPublished(String depositTxID)
{
log.trace("trading onDepositTxPublishedMessage " + depositTxID);
}
@Override
public void onDepositTxConfirmedUpdate(TransactionConfidence confidence)
{
log.trace("trading onDepositTxConfirmedUpdate");
}
@Override
public void onPayoutTxPublished(String payoutTxAsHex)
{
Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
trade.setPayoutTransaction(payoutTx);
trade.setState(Trade.State.COMPLETED);
log.debug("trading onPayoutTxPublishedMessage");
}
@Override
public void onFault(Throwable throwable, OffererAsBuyerProtocol.State state)
{
log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable);
}
@Override
public void onWaitingForPeerResponse(OffererAsBuyerProtocol.State state)
{
log.debug("Waiting for peers response at state " + state);
}
@Override
public void onCompleted(OffererAsBuyerProtocol.State state)
{
log.debug("Trade protocol completed at state " + state);
}
@Override
public void onWaitingForUserInteraction(OffererAsBuyerProtocol.State state)
{
log.debug("Waiting for UI activity at state " + state);
}
@Override
public void onDepositTxConfirmedInBlockchain()
{
log.trace("trading onDepositTxConfirmedInBlockchain");
}
});
this.offererAsBuyerProtocolMap.put(trade.getId(), offererAsBuyerProtocol);
offererAsBuyerProtocol.start();
protocolForOffererAsBuyer.start();
}
else
{
@ -305,13 +331,9 @@ public class Trading
createOffererAsBuyerProtocol(tradeId, sender);
takeOfferRequestListeners.stream().forEach(e -> e.onTakeOfferRequested(tradeId, sender));
}
else if (tradeMessage instanceof AcceptTakeOfferRequestMessage)
else if (tradeMessage instanceof RespondToTakeOfferRequestMessage)
{
takerAsSellerProtocolMap.get(tradeId).onAcceptTakeOfferRequestMessage();
}
else if (tradeMessage instanceof RejectTakeOfferRequestMessage)
{
takerAsSellerProtocolMap.get(tradeId).onRejectTakeOfferRequestMessage();
takerAsSellerProtocolMap.get(tradeId).onRespondToTakeOfferRequestMessage((RespondToTakeOfferRequestMessage) tradeMessage);
}
else if (tradeMessage instanceof TakeOfferFeePayedMessage)
{
@ -398,8 +420,12 @@ public class Trading
public Trade getTrade(String tradeId)
{
if (trades.containsKey(tradeId))
{
return trades.get(trades);
}
else
{
return null;
}
}
}

View File

@ -70,9 +70,13 @@ public class OrderBook implements OrderBookListener
public void loadOffers()
{
if (user.getCurrentBankAccount() != null)
{
messageFacade.getOffers(user.getCurrentBankAccount().getCurrency().getCurrencyCode());
}
else
{
messageFacade.getOffers(CurrencyUtil.getDefaultCurrency().getCurrencyCode());
}
}
public void removeOffer(Offer offer)
@ -86,10 +90,10 @@ public class OrderBook implements OrderBookListener
Offer offer = orderBookListItem.getOffer();
BankAccount currentBankAccount = user.getCurrentBankAccount();
if (orderBookFilter == null
|| currentBankAccount == null
|| orderBookFilter.getDirection() == null)
if (orderBookFilter == null || currentBankAccount == null || orderBookFilter.getDirection() == null)
{
return false;
}
// The users current bank account currency must match the offer currency (1 to 1)
boolean currencyResult = currentBankAccount.getCurrency().equals(offer.getCurrency());
@ -104,7 +108,9 @@ public class OrderBook implements OrderBookListener
// The requested amount must be lower or equal then the offer amount
boolean amountResult = true;
if (orderBookFilter.getAmount() > 0)
{
amountResult = orderBookFilter.getAmount() <= offer.getAmount().doubleValue();
}
// The requested trade direction must be opposite of the offerList trade direction
boolean directionResult = !orderBookFilter.getDirection().equals(offer.getDirection());
@ -114,9 +120,13 @@ public class OrderBook implements OrderBookListener
if (orderBookFilter.getPrice() > 0)
{
if (offer.getDirection() == Direction.SELL)
{
priceResult = orderBookFilter.getPrice() >= offer.getPrice();
}
else
{
priceResult = orderBookFilter.getPrice() <= offer.getPrice();
}
}
// The arbitrator defined in the offer must match one of the accepted arbitrators defined in the settings (1 to n)
@ -124,13 +134,7 @@ public class OrderBook implements OrderBookListener
//noinspection UnnecessaryLocalVariable
boolean result = currencyResult
&& countryResult
&& languageResult
&& amountResult
&& directionResult
&& priceResult
&& arbitratorResult;
boolean result = currencyResult && countryResult && languageResult && amountResult && directionResult && priceResult && arbitratorResult;
/*
log.debug("result = " + result +
@ -260,7 +264,9 @@ public class OrderBook implements OrderBookListener
for (Country country : list)
{
if (country.getCode().equals(countryToMatch.getCode()))
{
return true;
}
}
return false;
}
@ -272,7 +278,9 @@ public class OrderBook implements OrderBookListener
for (Locale locale2 : list1)
{
if (locale1.getLanguage().equals(locale2.getLanguage()))
{
return true;
}
}
}
return false;
@ -287,7 +295,9 @@ public class OrderBook implements OrderBookListener
try
{
if (arbitrator.getId().equals(arbitratorToMatch.getId()))
{
return true;
}
} catch (Exception e)
{
log.error(e.toString());

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.tasks;
package io.bitsquare.trade.protocol;
public interface FaultHandler
{

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.tasks;
package io.bitsquare.trade.protocol;
public interface ResultHandler
{

View File

@ -1,22 +0,0 @@
package io.bitsquare.trade.protocol.messages.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
public class AcceptTakeOfferRequestMessage implements Serializable, TradeMessage
{
private static final long serialVersionUID = 6177387534087739018L;
private final String tradeId;
public AcceptTakeOfferRequestMessage(String tradeId)
{
this.tradeId = tradeId;
}
@Override
public String getTradeId()
{
return tradeId;
}
}

View File

@ -1,21 +0,0 @@
package io.bitsquare.trade.protocol.messages.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
public class RejectTakeOfferRequestMessage implements Serializable, TradeMessage
{
private static final long serialVersionUID = -8088557759642128139L;
private final String tradeId;
public RejectTakeOfferRequestMessage(String tradeId)
{
this.tradeId = tradeId;
}
@Override
public String getTradeId()
{
return tradeId;
}
}

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.offerer;
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
@ -16,7 +16,8 @@ public class BankTransferInitedMessage implements Serializable, TradeMessage
private BigInteger takerPaybackAmount;
private String offererPayoutAddress;
public BankTransferInitedMessage(String tradeId, String depositTxAsHex,
public BankTransferInitedMessage(String tradeId,
String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
BigInteger offererPaybackAmount,

View File

@ -1,10 +1,10 @@
package io.bitsquare.trade.protocol.tasks.offerer;
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -24,11 +24,7 @@ public class CreateDepositTx
try
{
String offererPubKey = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
Transaction transaction = walletFacade.offererCreatesMSTxAndAddPayment(collateralAmount,
offererPubKey,
takerMultiSigPubKey,
arbitratorPubKeyAsHex,
tradeId);
Transaction transaction = walletFacade.offererCreatesMSTxAndAddPayment(collateralAmount, offererPubKey, takerMultiSigPubKey, arbitratorPubKeyAsHex, tradeId);
String preparedOffererDepositTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex();

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.offerer;
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;

View File

@ -0,0 +1,44 @@
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.FaultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HandleTakeOfferRequest
{
private static final Logger log = LoggerFactory.getLogger(HandleTakeOfferRequest.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade.State tradeState, String tradeId)
{
boolean takeOfferRequestAccepted = tradeState == Trade.State.OPEN;
if (!takeOfferRequestAccepted)
{
log.info("Received take offer request but the offer not marked as open anymore.");
}
messageFacade.sendTradeMessage(peerAddress, new RespondToTakeOfferRequestMessage(tradeId, takeOfferRequestAccepted), new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RespondToTakeOfferRequestMessage successfully arrived at peer");
resultHandler.onResult(takeOfferRequestAccepted);
}
@Override
public void onFailed()
{
log.error("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer"));
}
});
}
public interface ResultHandler
{
void onResult(boolean takeOfferRequestAccepted);
}
}

View File

@ -10,368 +10,39 @@ import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.tasks.offerer.*;
import io.bitsquare.trade.protocol.taker.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.taker.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.taker.TakeOfferFeePayedMessage;
import io.bitsquare.user.User;
import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer.
* That class handles the role of the offerer as the Bitcoin buyer.
* <p>
* This class handles the role of the offerer as the Bitcoin buyer.
* <p>
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
* Any data from incoming messages need to be validated before further processing.
*/
public class OffererAsBuyerProtocol
public class ProtocolForOffererAsBuyer
{
private static final Logger log = LoggerFactory.getLogger(OffererAsBuyerProtocol.class);
public final PeerAddress peerAddress;
// provided data
private final String id;
private final Trade trade;
private final OffererAsBuyerProtocolListener listener;
private final MessageFacade messageFacade;
private final WalletFacade walletFacade;
private final BlockChainFacade blockChainFacade;
private final CryptoFacade cryptoFacade;
private final User user;
private final String tradeId;
private final Offer offer;
// data written/read by tasks
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
// data written by messages, read by tasks
private String takeOfferFeeTxId;
private String takerMultiSigPubKey;
private String takerPayoutAddress;
private String peersAccountId;
private BankAccount peersBankAccount;
private String takerMessagePubKey;
private String peersContractAsJson;
private String signedTakerDepositTxAsHex;
private String txConnOutAsHex;
private String txScriptSigAsHex;
private long takerTxOutIndex;
// private
private State state;
public OffererAsBuyerProtocol(Trade trade,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user,
OffererAsBuyerProtocolListener listener)
{
this.trade = trade;
this.peerAddress = peerAddress;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
this.user = user;
id = trade.getId();
tradeId = trade.getId();
offer = trade.getOffer();
state = State.Init;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public void start()
{
log.debug("start");
HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFault, peerAddress, messageFacade, trade.getState(), tradeId);
state = State.HandleTakeOfferRequest;
}
public void onResultHandleTakeOfferRequest(Trade.State tradeState)
{
log.debug("onResultHandleTakeOfferRequest");
trade.setState(tradeState);
messageFacade.removeOffer(offer);
listener.onOfferAccepted(offer);
listener.onWaitingForPeerResponse(state);
}
public void onTakeOfferFeePayedMessage(TakeOfferFeePayedMessage message)
{
log.debug("onTakeOfferFeePayedMessage");
// validation
checkState(state == State.HandleTakeOfferRequest);
checkNotNull(message);
String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
BigInteger tradeAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getTradeAmount()));
String takerMultiSigPubKey = nonEmptyStringOf(message.getTakerMultiSigPubKey());
// apply new state
state = State.onTakeOfferFeePayedMessage;
this.takeOfferFeeTxId = takeOfferFeeTxId;
this.takerMultiSigPubKey = takerMultiSigPubKey;
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
trade.setTradeAmount(tradeAmount);
// next task
VerifyTakeOfferFeePayment.run(this::onResultVerifyTakeOfferFeePayment, this::onFault, walletFacade, takeOfferFeeTxId);
state = State.VerifyTakeOfferFeePayment;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultVerifyTakeOfferFeePayment()
{
log.debug("onResultVerifyTakeOfferFeePayment");
BigInteger collateralAmount = trade.getCollateralAmount();
String arbitratorPubKeyAsHex = offer.getArbitrator().getPubKeyAsHex();
CreateDepositTx.run(this::onResultCreateDepositTx,
this::onFault,
walletFacade,
tradeId,
collateralAmount,
takerMultiSigPubKey,
arbitratorPubKeyAsHex);
state = State.CreateDepositTx;
}
public void onResultCreateDepositTx(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex)
{
log.debug("onResultCreateDepositTx");
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
this.offererTxOutIndex = offererTxOutIndex;
BankAccount bankAccount = user.getBankAccount(trade.getOffer().getBankAccountId());
String accountId = user.getAccountId();
RequestTakerDepositPayment.run(this::onResultRequestTakerDepositPayment,
this::onFault,
peerAddress,
messageFacade,
tradeId,
bankAccount,
accountId,
offererPubKey,
preparedOffererDepositTxAsHex,
offererTxOutIndex);
state = State.RequestTakerDepositPayment;
}
public void onResultRequestTakerDepositPayment()
{
log.debug("onResultRequestTakerDepositPayment");
listener.onWaitingForPeerResponse(state);
}
public void onRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message)
{
log.debug("onRequestOffererPublishDepositTxMessage");
// validation
checkState(state == State.RequestTakerDepositPayment);
checkNotNull(message);
String takerPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
String peersAccountId = nonEmptyStringOf(message.getAccountId());
BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
String takerMessagePubKey = nonEmptyStringOf(message.getTakerMessagePubKey());
String peersContractAsJson = nonEmptyStringOf(message.getContractAsJson());
String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// apply new state
state = State.onRequestOffererPublishDepositTxMessage;
this.takerPayoutAddress = takerPayoutAddress;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.takerMessagePubKey = takerMessagePubKey;
this.peersContractAsJson = peersContractAsJson;
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
this.txConnOutAsHex = txConnOutAsHex;
this.txScriptSigAsHex = txScriptSigAsHex;
this.takerTxOutIndex = takerTxOutIndex;
// next task
VerifyTakerAccount.run(this::onResultVerifyTakerAccount, this::onFault, blockChainFacade, peersAccountId, peersBankAccount);
state = State.VerifyTakerAccount;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultVerifyTakerAccount()
{
log.debug("onResultVerifyTakerAccount");
String accountId = user.getAccountId();
BigInteger tradeAmount = trade.getTradeAmount();
String messagePubKeyAsHex = user.getMessagePubKeyAsHex();
BankAccount bankAccount = user.getBankAccount(offer.getBankAccountId());
ECKey registrationKey = walletFacade.getRegistrationAddressInfo().getKey();
VerifyAndSignContract.run(this::onResultVerifyAndSignContract,
this::onFault,
cryptoFacade,
accountId,
tradeAmount,
takeOfferFeeTxId,
messagePubKeyAsHex,
offer,
peersAccountId,
bankAccount,
peersBankAccount,
takerMessagePubKey,
peersContractAsJson,
registrationKey);
state = State.VerifyAndSignContract;
}
public void onResultVerifyAndSignContract(Contract contract, String contractAsJson, String signature)
{
log.debug("onResultVerifyAndSignContract");
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
SignAndPublishDepositTx.run(this::onResultSignAndPublishDepositTx,
this::onFault,
walletFacade,
preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex);
state = State.SignAndPublishDepositTx;
}
public void onResultSignAndPublishDepositTx(Transaction transaction)
{
log.debug("onResultSignAndPublishDepositTx");
trade.setDepositTransaction(transaction);
listener.onDepositTxPublished(transaction.getHashAsString());
Transaction depositTransaction = trade.getDepositTransaction();
SendDepositTxIdToTaker.run(this::onResultSendDepositTxIdToTaker, this::onFault, peerAddress, messageFacade, tradeId, depositTransaction);
state = State.SendDepositTxIdToTaker;
}
public void onResultSendDepositTxIdToTaker()
{
log.debug("onResultSendDepositTxIdToTaker");
SetupListenerForBlockChainConfirmation.run(this::onResultSetupListenerForBlockChainConfirmation, this::onFault, trade.getDepositTransaction(), listener);
state = State.SetupListenerForBlockChainConfirmation;
}
public void onResultSetupListenerForBlockChainConfirmation()
{
log.debug("onResultSetupListenerForBlockChainConfirmation");
state = State.onResultSetupListenerForBlockChainConfirmation;
listener.onWaitingForUserInteraction(state);
}
// Triggered from UI event: Button click "Bank transfer inited"
public void onUIEventBankTransferInited()
{
log.debug("onUIEventBankTransferInited");
// validation
checkState(state == State.onResultSetupListenerForBlockChainConfirmation);
state = State.onUIEventBankTransferInited;
// next task
String depositTransactionId = trade.getDepositTransaction().getHashAsString();
String offererPayoutAddress = walletFacade.getAddressInfoByTradeID(tradeId).getAddressString();
BigInteger collateral = trade.getCollateralAmount();
BigInteger tradeAmount = trade.getTradeAmount();
SendSignedPayoutTx.run(this::onResultSendSignedPayoutTx, this::onFault, peerAddress, messageFacade, walletFacade, tradeId, takerPayoutAddress, offererPayoutAddress, depositTransactionId, collateral, tradeAmount);
state = State.SendSignedPayoutTx;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultSendSignedPayoutTx()
{
log.debug("onResultSendSignedPayoutTx");
listener.onWaitingForPeerResponse(state);
}
public void onPayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage)
{
log.debug("onPayoutTxPublishedMessage");
// validation
checkState(state == State.SendSignedPayoutTx);
String payoutTxAsHex = nonEmptyStringOf(tradeMessage.getPayoutTxAsHex());
state = State.onPayoutTxPublishedMessage;
// next task
listener.onPayoutTxPublished(payoutTxAsHex);
listener.onCompleted(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private static final Logger log = LoggerFactory.getLogger(ProtocolForOffererAsBuyer.class);
private final String arbitratorPubKey;
private final BigInteger collateral;
private final BankAccount bankAccount;
private final String accountId;
private final BigInteger tradeAmount;
private final String messagePubKey;
private final ECKey accountKey;
private final String payoutAddress;
public enum State
{
@ -397,4 +68,351 @@ public class OffererAsBuyerProtocol
onPayoutTxPublishedMessage
}
private final Trade trade;
private final PeerAddress peerAddress;
private final MessageFacade messageFacade;
private final WalletFacade walletFacade;
private final BlockChainFacade blockChainFacade;
private final CryptoFacade cryptoFacade;
private final ProtocolForOffererAsBuyerListener listener;
private final String id;
private final String tradeId;
private final Offer offer;
private State state;
// data written/read by tasks
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
// data written by messages, read by tasks
private String takeOfferFeeTxId;
private String takerPubKey;
private String peersPayoutAddress;
private String peersAccountId;
private BankAccount peersBankAccount;
private String peersMessagePubKey;
private String peersContractAsJson;
private String signedTakerDepositTxAsHex;
private String txConnOutAsHex;
private String txScriptSigAsHex;
private long takerTxOutIndex;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ProtocolForOffererAsBuyer(Trade trade,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user,
ProtocolForOffererAsBuyerListener listener)
{
this.trade = trade;
this.peerAddress = peerAddress;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
id = trade.getId();
tradeId = trade.getId();
offer = trade.getOffer();
arbitratorPubKey = offer.getArbitrator().getPubKeyAsHex();
collateral = trade.getCollateralAmount();
bankAccount = user.getBankAccount(trade.getOffer().getBankAccountId());
accountId = user.getAccountId();
tradeAmount = trade.getTradeAmount();
messagePubKey = user.getMessagePubKeyAsHex();
accountKey = walletFacade.getRegistrationAddressInfo().getKey();
payoutAddress = walletFacade.getAddressInfoByTradeID(tradeId).getAddressString();
state = State.Init;
}
public void start()
{
log.debug("start called ");
HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFault, peerAddress, messageFacade, trade.getState(), tradeId);
state = State.HandleTakeOfferRequest;
}
public void onResultHandleTakeOfferRequest(boolean takeOfferRequestAccepted)
{
log.debug("onResultHandleTakeOfferRequest called ");
if (takeOfferRequestAccepted)
{
trade.setState(Trade.State.ACCEPTED);
messageFacade.removeOffer(offer);
listener.onOfferAccepted(offer);
listener.onWaitingForPeerResponse(state);
}
else
{
log.info("Finish here as we have already the offer accepted.");
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onTakeOfferFeePayedMessage(@NotNull TakeOfferFeePayedMessage message)
{
log.debug("onTakeOfferFeePayedMessage called ");
// validation
checkState(state == State.HandleTakeOfferRequest);
checkArgument(tradeId.equals(message.getTradeId()));
String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
BigInteger tradeAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getTradeAmount()));
String takerPubKey = nonEmptyStringOf(message.getTakerPubKey());
// apply new state
state = State.onTakeOfferFeePayedMessage;
this.takeOfferFeeTxId = takeOfferFeeTxId;
this.takerPubKey = takerPubKey;
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
trade.setTradeAmount(tradeAmount);
// next task
VerifyTakeOfferFeePayment.run(this::onResultVerifyTakeOfferFeePayment, this::onFault, walletFacade, this.takeOfferFeeTxId);
state = State.VerifyTakeOfferFeePayment;
}
public void onResultVerifyTakeOfferFeePayment()
{
log.debug("onResultVerifyTakeOfferFeePayment called ");
CreateDepositTx.run(this::onResultCreateDepositTx, this::onFault, walletFacade, tradeId, collateral, takerPubKey, arbitratorPubKey);
state = State.CreateDepositTx;
}
public void onResultCreateDepositTx(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex)
{
log.debug("onResultCreateDepositTx called ");
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
this.offererTxOutIndex = offererTxOutIndex;
RequestTakerDepositPayment.run(this::onResultRequestTakerDepositPayment,
this::onFault,
peerAddress,
messageFacade,
tradeId,
bankAccount,
accountId,
offererPubKey,
preparedOffererDepositTxAsHex,
offererTxOutIndex);
state = State.RequestTakerDepositPayment;
}
public void onResultRequestTakerDepositPayment()
{
log.debug("onResultRequestTakerDepositPayment called ");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message)
{
log.debug("onRequestOffererPublishDepositTxMessage called ");
// validation
checkState(state == State.RequestTakerDepositPayment);
checkArgument(tradeId.equals(message.getTradeId()));
String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
String peersMessagePubKey = nonEmptyStringOf(message.getTakerMessagePubKey());
String peersContractAsJson = nonEmptyStringOf(message.getTakerContractAsJson());
String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// apply new state
state = State.onRequestOffererPublishDepositTxMessage;
this.peersPayoutAddress = peersPayoutAddress;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.peersMessagePubKey = peersMessagePubKey;
this.peersContractAsJson = peersContractAsJson;
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
this.txConnOutAsHex = txConnOutAsHex;
this.txScriptSigAsHex = txScriptSigAsHex;
this.takerTxOutIndex = takerTxOutIndex;
// next task
VerifyTakerAccount.run(this::onResultVerifyTakerAccount, this::onFault, blockChainFacade, this.peersAccountId, this.peersBankAccount);
state = State.VerifyTakerAccount;
}
public void onResultVerifyTakerAccount()
{
log.debug("onResultVerifyTakerAccount called ");
VerifyAndSignContract.run(this::onResultVerifyAndSignContract,
this::onFault,
cryptoFacade,
accountId,
tradeAmount,
takeOfferFeeTxId,
messagePubKey,
offer,
peersAccountId,
bankAccount,
peersBankAccount,
peersMessagePubKey,
peersContractAsJson,
accountKey);
state = State.VerifyAndSignContract;
}
public void onResultVerifyAndSignContract(Contract contract, String contractAsJson, String signature)
{
log.debug("onResultVerifyAndSignContract called ");
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
SignAndPublishDepositTx.run(this::onResultSignAndPublishDepositTx,
this::onFault,
walletFacade,
preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex);
state = State.SignAndPublishDepositTx;
}
public void onResultSignAndPublishDepositTx(Transaction depositTransaction)
{
log.debug("onResultSignAndPublishDepositTx called ");
trade.setDepositTransaction(depositTransaction);
listener.onDepositTxPublished(depositTransaction.getHashAsString());
SendDepositTxIdToTaker.run(this::onResultSendDepositTxIdToTaker, this::onFault, peerAddress, messageFacade, tradeId, depositTransaction);
state = State.SendDepositTxIdToTaker;
}
public void onResultSendDepositTxIdToTaker()
{
log.debug("onResultSendDepositTxIdToTaker called ");
SetupListenerForBlockChainConfirmation.run(this::onResultSetupListenerForBlockChainConfirmation, this::onFault, trade.getDepositTransaction(), listener);
state = State.SetupListenerForBlockChainConfirmation;
}
public void onResultSetupListenerForBlockChainConfirmation()
{
log.debug("onResultSetupListenerForBlockChainConfirmation called ");
state = State.onResultSetupListenerForBlockChainConfirmation;
listener.onWaitingForUserInteraction(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered from UI event: Button click "Bank transfer inited"
public void onUIEventBankTransferInited()
{
log.debug("onUIEventBankTransferInited called ");
// validation
checkState(state == State.onResultSetupListenerForBlockChainConfirmation);
state = State.onUIEventBankTransferInited;
// next task
String depositTransactionId = trade.getDepositTransaction().getHashAsString();
SendSignedPayoutTx.run(this::onResultSendSignedPayoutTx,
this::onFault,
peerAddress,
messageFacade,
walletFacade,
tradeId,
peersPayoutAddress,
payoutAddress,
depositTransactionId,
collateral,
tradeAmount);
state = State.SendSignedPayoutTx;
}
public void onResultSendSignedPayoutTx()
{
log.debug("onResultSendSignedPayoutTx called ");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onPayoutTxPublishedMessage(PayoutTxPublishedMessage message)
{
log.debug("onPayoutTxPublishedMessage called ");
// validation
checkState(state == State.SendSignedPayoutTx);
checkArgument(tradeId.equals(message.getTradeId()));
String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex());
state = State.onPayoutTxPublishedMessage;
// next task
listener.onPayoutTxPublished(payoutTxAsHex);
listener.onCompleted(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
}

View File

@ -3,7 +3,7 @@ package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.TransactionConfidence;
import io.bitsquare.trade.Offer;
public interface OffererAsBuyerProtocolListener
public interface ProtocolForOffererAsBuyerListener
{
void onOfferAccepted(Offer offer);
@ -15,11 +15,11 @@ public interface OffererAsBuyerProtocolListener
void onPayoutTxPublished(String payoutTxID);
void onFault(Throwable throwable, OffererAsBuyerProtocol.State state);
void onFault(Throwable throwable, ProtocolForOffererAsBuyer.State state);
void onWaitingForPeerResponse(OffererAsBuyerProtocol.State state);
void onWaitingForPeerResponse(ProtocolForOffererAsBuyer.State state);
void onCompleted(OffererAsBuyerProtocol.State state);
void onCompleted(ProtocolForOffererAsBuyer.State state);
void onWaitingForUserInteraction(OffererAsBuyerProtocol.State state);
void onWaitingForUserInteraction(ProtocolForOffererAsBuyer.State state);
}

View File

@ -1,11 +1,10 @@
package io.bitsquare.trade.protocol.tasks.offerer;
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.offerer.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -25,12 +24,7 @@ public class RequestTakerDepositPayment
String preparedOffererDepositTxAsHex,
long offererTxOutIndex)
{
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(tradeId,
bankAccount,
accountId,
offererPubKey,
preparedOffererDepositTxAsHex,
offererTxOutIndex);
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(tradeId, bankAccount, accountId, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{
@Override

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.offerer;
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.msg.TradeMessage;
@ -9,7 +9,6 @@ public class RequestTakerDepositPaymentMessage implements Serializable, TradeMes
private static final long serialVersionUID = -3988720410493712913L;
private final String tradeId;
private BankAccount bankAccount;
private String accountID;
private String offererPubKey;
@ -37,7 +36,7 @@ public class RequestTakerDepositPaymentMessage implements Serializable, TradeMes
return bankAccount;
}
public String getAccountID()
public String getAccountId()
{
return accountID;
}

View File

@ -0,0 +1,28 @@
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
public class RespondToTakeOfferRequestMessage implements Serializable, TradeMessage
{
private static final long serialVersionUID = 6177387534087739018L;
private final String tradeId;
private boolean takeOfferRequestAccepted;
public RespondToTakeOfferRequestMessage(String tradeId, boolean takeOfferRequestAccepted)
{
this.tradeId = tradeId;
this.takeOfferRequestAccepted = takeOfferRequestAccepted;
}
@Override
public String getTradeId()
{
return tradeId;
}
public boolean isTakeOfferRequestAccepted()
{
return takeOfferRequestAccepted;
}
}

View File

@ -1,12 +1,11 @@
package io.bitsquare.trade.protocol.tasks.offerer;
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,12 +1,11 @@
package io.bitsquare.trade.protocol.tasks.offerer;
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.ECKey;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import java.math.BigInteger;
import javafx.util.Pair;
import net.tomp2p.peers.PeerAddress;
@ -34,11 +33,7 @@ public class SendSignedPayoutTx
BigInteger offererPaybackAmount = tradeAmount.add(collateral);
BigInteger takerPaybackAmount = collateral;
Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransactionId,
offererPaybackAmount,
takerPaybackAmount,
takerPayoutAddress,
tradeId);
Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransactionId, offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, tradeId);
ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString();
@ -46,12 +41,12 @@ public class SendSignedPayoutTx
String depositTxAsHex = result.getValue();
BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(tradeId,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{

View File

@ -0,0 +1,38 @@
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SetupListenerForBlockChainConfirmation
{
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, Transaction depositTransaction, ProtocolForOffererAsBuyerListener listener)
{ //TODO
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().addEventListener(new TransactionConfidence.Listener()
{
@Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason)
{
log.trace("onConfidenceChanged " + tx.getConfidence());
if (reason == ChangeReason.SEEN_PEERS)
{
listener.onDepositTxConfirmedUpdate(tx.getConfidence());
}
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
listener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().removeEventListener(this);
log.trace("Tx is in blockchain");
resultHandler.onResult();
}
}
});
}
}

View File

@ -0,0 +1,60 @@
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishDepositTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
String preparedOffererDepositTxAsHex,
String signedTakerDepositTxAsHex,
String txConnOutAsHex,
String txScriptSigAsHex,
long offererTxOutIndex,
long takerTxOutIndex)
{
try
{
walletFacade.offererSignAndPublishTx(preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex,
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.trace("offererSignAndPublishTx succeeded " + transaction);
resultHandler.onResult(transaction);
}
@Override
public void onFailure(Throwable t)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(Transaction depositTransaction);
}
}

View File

@ -1,11 +1,11 @@
package io.bitsquare.trade.protocol.tasks.offerer;
package io.bitsquare.trade.protocol.offerer;
import com.google.bitcoin.core.ECKey;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.util.Utilities;
import java.math.BigInteger;
import org.slf4j.Logger;
@ -30,15 +30,7 @@ public class VerifyAndSignContract
String peersContractAsJson,
ECKey registrationKey)
{
Contract contract = new Contract(offer,
tradeAmount,
takeOfferFeeTxId,
accountId,
peersAccountId,
bankAccount,
peersBankAccount,
messagePubKeyAsHex,
takerMessagePubKey);
Contract contract = new Contract(offer, tradeAmount, takeOfferFeeTxId, accountId, peersAccountId, bankAccount, peersBankAccount, messagePubKeyAsHex, takerMessagePubKey);
String contractAsJson = Utilities.objectToJson(contract);
// log.trace("Offerer contract created: " + contract);

View File

@ -1,8 +1,8 @@
package io.bitsquare.trade.protocol.tasks.offerer;
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -0,0 +1,20 @@
package io.bitsquare.trade.protocol.offerer;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.shared.VerifyPeerAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyTakerAccount
{
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{
VerifyPeerAccount.run(resultHandler, faultHandler, blockChainFacade, peersAccountId, peersBankAccount);
}
}

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock;
package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl.
class BuyOffererPaymentProcess extends PaymentProcess

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock;
package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl.
public class BuyTakerPaymentProcess extends PaymentProcess

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock;
package io.bitsquare.trade.protocol.old;
import com.google.inject.Inject;
import io.bitsquare.btc.BlockChainFacade;

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock;
package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl.
class SellOffererPaymentProcess extends PaymentProcess

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.mock;
package io.bitsquare.trade.protocol.old;
//TODO not used but let it for reference until all use cases are impl.
class SellTakerPaymentProcess extends PaymentProcess

View File

@ -1,15 +1,15 @@
package io.bitsquare.trade.protocol.tasks.offerer;
package io.bitsquare.trade.protocol.shared;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyTakerAccount
public class VerifyPeerAccount
{
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class);
private static final Logger log = LoggerFactory.getLogger(VerifyPeerAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{

View File

@ -0,0 +1,51 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.ECKey;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.util.Utilities;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateAndSignContract
{
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
CryptoFacade cryptoFacade,
Offer offer,
BigInteger tradeAmount,
String takeOfferFeeTxId,
String accountId,
BankAccount bankAccount,
String peersMessagePubKeyAsHex,
String messagePubKeyAsHex,
String peersAccountId,
BankAccount peersBankAccount,
ECKey registrationKey)
{
try
{
Contract contract = new Contract(offer, tradeAmount, takeOfferFeeTxId, peersAccountId, accountId, peersBankAccount, bankAccount, peersMessagePubKeyAsHex, messagePubKeyAsHex);
String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
resultHandler.onResult(contract, contractAsJson, signature);
} catch (Throwable t)
{
log.error("Exception at sign contract " + t);
faultHandler.onFault(t);
}
}
public interface ResultHandler
{
void onResult(Contract contract, String contractAsJson, String signature);
}
}

View File

@ -1,8 +1,8 @@
package io.bitsquare.trade.protocol.tasks.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.GetPeerAddressListener;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -0,0 +1,54 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayDeposit
{
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
BigInteger collateral,
BigInteger tradeAmount,
String tradeId,
String pubKeyForThatTrade,
String arbitratorPubKey,
String offererPubKey,
String preparedOffererDepositTxAsHex)
{
try
{
BigInteger amountToPay = tradeAmount.add(collateral);
BigInteger msOutputAmount = amountToPay.add(collateral);
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(amountToPay,
msOutputAmount,
offererPubKey,
pubKeyForThatTrade,
arbitratorPubKey,
preparedOffererDepositTxAsHex,
tradeId);
log.trace("sharedModel.signedTakerDepositTx: " + signedTakerDepositTx);
resultHandler.onResult(signedTakerDepositTx);
} catch (InsufficientMoneyException e)
{
log.error("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e);
faultHandler.onFault(new Exception("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e));
}
}
public interface ResultHandler
{
void onResult(Transaction signedTakerDepositTx);
}
}

View File

@ -1,10 +1,10 @@
package io.bitsquare.trade.protocol.tasks.taker;
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -23,7 +23,7 @@ public class PayTakeOfferFee
public void onSuccess(Transaction transaction)
{
log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString());
resultHandler.onResult(transaction);
resultHandler.onResult(transaction.getHashAsString());
}
@Override
@ -42,7 +42,7 @@ public class PayTakeOfferFee
public interface ResultHandler
{
void onResult(Transaction transaction);
void onResult(String takeOfferFeeTxId);
}
}

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;

View File

@ -0,0 +1,400 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.offerer.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.offerer.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.offerer.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.offerer.RespondToTakeOfferRequestMessage;
import io.bitsquare.user.User;
import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer.
* That class handles the role of the taker as the Bitcoin seller.
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
*/
public class ProtocolForTakerAsSeller
{
private static final Logger log = LoggerFactory.getLogger(ProtocolForTakerAsSeller.class);
public enum State
{
Init,
GetPeerAddress,
RequestTakeOffer,
PayTakeOfferFee,
onRequestTakerDepositPaymentMessage,
SendTakeOfferFeePayedTxId,
VerifyOffererAccount,
CreateAndSignContract,
PayDeposit,
SendSignedTakerDepositTxAsHex,
onDepositTxPublishedMessage,
onBankTransferInitedMessage,
onUIEventFiatReceived,
SignAndPublishPayoutTx,
SendPayoutTxToOfferer
}
// provided data
private final Trade trade;
private final ProtocolForTakerAsSellerListener listener;
private final MessageFacade messageFacade;
private final WalletFacade walletFacade;
private final BlockChainFacade blockChainFacade;
private final CryptoFacade cryptoFacade;
// derived
private final String id;
private final Offer offer;
private final String tradeId;
private final BankAccount bankAccount;
private final String accountId;
private final String messagePubKey;
private final BigInteger tradeAmount;
private final String pubKeyForThatTrade;
private final ECKey accountKey;
private final String peersMessagePubKey;
private final BigInteger collateral;
private final String arbitratorPubKey;
// written/read by task
private PeerAddress peerAddress;
// written by messages, read by tasks
private String peersAccountId;
private BankAccount peersBankAccount;
private String peersPubKey;
private String preparedPeersDepositTxAsHex;
private long peersTxOutIndex;
private String depositTxAsHex;
private String offererSignatureR;
private String offererSignatureS;
private BigInteger offererPaybackAmount;
private BigInteger takerPaybackAmount;
private String offererPayoutAddress;
// state
private State state;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ProtocolForTakerAsSeller(Trade trade,
ProtocolForTakerAsSellerListener listener,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user)
{
this.trade = trade;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
offer = trade.getOffer();
tradeId = trade.getId();
tradeAmount = trade.getTradeAmount();
collateral = trade.getCollateralAmount();
arbitratorPubKey = trade.getOffer().getArbitrator().getPubKeyAsHex();
pubKeyForThatTrade = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
bankAccount = user.getBankAccount(offer.getBankAccountId());
accountId = user.getAccountId();
messagePubKey = user.getMessagePubKeyAsHex();
peersMessagePubKey = offer.getMessagePubKeyAsHex();
accountKey = walletFacade.getRegistrationAddressInfo().getKey();
id = trade.getId();
state = State.Init;
}
public void start()
{
log.debug("start called");
GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, messageFacade, peersMessagePubKey);
state = State.GetPeerAddress;
}
public void onResultGetPeerAddress(PeerAddress peerAddress)
{
log.debug(" called");
this.peerAddress = peerAddress;
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, peerAddress, messageFacade, tradeId);
state = State.RequestTakeOffer;
}
public void onResultRequestTakeOffer()
{
log.debug(" called");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message)
{
log.debug("onRespondToTakeOfferRequestMessage called");
checkState(state == State.RequestTakeOffer);
checkArgument(tradeId.equals(message.getTradeId()));
if (message.isTakeOfferRequestAccepted())
{
PayTakeOfferFee.run(this::onResultPayTakeOfferFee, this::onFault, walletFacade, tradeId);
state = State.PayTakeOfferFee;
}
else
{
listener.onTakeOfferRequestRejected(trade);
}
}
public void onResultPayTakeOfferFee(String takeOfferFeeTxId)
{
log.debug("onResultPayTakeOfferFee called");
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
SendTakeOfferFeePayedTxId.run(this::onResultSendTakeOfferFeePayedTxId, this::onFault, peerAddress, messageFacade, tradeId, takeOfferFeeTxId, tradeAmount, pubKeyForThatTrade);
state = State.SendTakeOfferFeePayedTxId;
}
public void onResultSendTakeOfferFeePayedTxId()
{
log.debug("onResultSendTakeOfferFeePayedTxId called");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage message)
{
log.debug("onRequestTakerDepositPaymentMessage called");
// validation
checkState(state == State.SendTakeOfferFeePayedTxId);
checkArgument(tradeId.equals(message.getTradeId()));
String peersAccountId = nonEmptyStringOf(message.getAccountId());
BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
String offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
String preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
// apply new state
state = State.onRequestTakerDepositPaymentMessage;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.peersPubKey = offererPubKey;
this.preparedPeersDepositTxAsHex = preparedOffererDepositTxAsHex;
this.peersTxOutIndex = offererTxOutIndex;
// next task
VerifyOffererAccount.run(this::onResultVerifyOffererAccount, this::onFault, blockChainFacade, peersAccountId, peersBankAccount);
state = State.VerifyOffererAccount;
}
public void onResultVerifyOffererAccount()
{
log.debug("onResultVerifyOffererAccount called");
String takeOfferFeeTxId = trade.getTakeOfferFeeTxId();
CreateAndSignContract.run(this::onResultCreateAndSignContract,
this::onFault,
cryptoFacade,
offer,
tradeAmount,
takeOfferFeeTxId,
accountId,
bankAccount,
peersMessagePubKey,
messagePubKey,
peersAccountId,
peersBankAccount,
accountKey);
state = State.CreateAndSignContract;
}
public void onResultCreateAndSignContract(Contract contract, String contractAsJson, String signature)
{
log.debug("onResultCreateAndSignContract called");
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
PayDeposit.run(this::onResultPayDeposit, this::onFault, walletFacade, collateral, tradeAmount, tradeId, pubKeyForThatTrade, arbitratorPubKey, peersPubKey, preparedPeersDepositTxAsHex);
state = State.PayDeposit;
}
public void onResultPayDeposit(Transaction signedTakerDepositTx)
{
log.debug("onResultPayDeposit called");
String contractAsJson = trade.getContractAsJson();
String takerSignature = trade.getTakerSignature();
SendSignedTakerDepositTxAsHex.run(this::onResultSendSignedTakerDepositTxAsHex,
this::onFault,
peerAddress,
messageFacade,
walletFacade,
bankAccount,
accountId,
messagePubKey,
tradeId,
contractAsJson,
takerSignature,
signedTakerDepositTx,
peersTxOutIndex);
state = State.SendSignedTakerDepositTxAsHex;
}
public void onResultSendSignedTakerDepositTxAsHex()
{
log.debug(" called");
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// informational, does only trigger UI feedback/update
public void onDepositTxPublishedMessage(DepositTxPublishedMessage message)
{
log.debug("onDepositTxPublishedMessage called");
checkState(state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
checkArgument(tradeId.equals(message.getTradeId()));
state = State.onDepositTxPublishedMessage;
listener.onDepositTxPublished(walletFacade.takerCommitDepositTx(message.getDepositTxAsHex()));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// informational, store data for later, does only trigger UI feedback/update
public void onBankTransferInitedMessage(BankTransferInitedMessage message)
{
log.debug("onBankTransferInitedMessage called");
// validate
checkState(state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
checkArgument(tradeId.equals(message.getTradeId()));
String depositTxAsHex = nonEmptyStringOf(message.getDepositTxAsHex());
String offererSignatureR = nonEmptyStringOf(message.getOffererSignatureR());
String offererSignatureS = nonEmptyStringOf(message.getOffererSignatureS());
BigInteger offererPaybackAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getOffererPaybackAmount()));
BigInteger takerPaybackAmount = nonNegativeBigIntegerOf(nonZeroBigIntegerOf(message.getTakerPaybackAmount()));
String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress());
// apply state
state = State.onBankTransferInitedMessage;
this.depositTxAsHex = depositTxAsHex;
this.offererSignatureR = offererSignatureR;
this.offererSignatureS = offererSignatureS;
this.offererPaybackAmount = offererPaybackAmount;
this.takerPaybackAmount = takerPaybackAmount;
this.offererPayoutAddress = offererPayoutAddress;
listener.onBankTransferInited(message.getTradeId());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event
///////////////////////////////////////////////////////////////////////////////////////////
// User clicked the "bank transfer received" button, so we release the funds for pay out
public void onUIEventFiatReceived()
{
log.debug("onUIEventFiatReceived called");
checkState(state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
state = State.onUIEventFiatReceived;
SignAndPublishPayoutTx.run(this::onResultSignAndPublishPayoutTx,
this::onFault,
walletFacade,
tradeId,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
state = State.SignAndPublishPayoutTx;
}
public void onResultSignAndPublishPayoutTx(String transactionId, String payoutTxAsHex)
{
log.debug("onResultSignAndPublishPayoutTx called");
listener.onPayoutTxPublished(trade, transactionId);
SendPayoutTxToOfferer.run(this::onResultSendPayoutTxToOfferer, this::onFault, peerAddress, messageFacade, tradeId, payoutTxAsHex);
state = State.SendPayoutTxToOfferer;
}
public void onResultSendPayoutTxToOfferer()
{
log.debug("onResultSendPayoutTxToOfferer called");
listener.onCompleted(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
}

View File

@ -2,7 +2,7 @@ package io.bitsquare.trade.protocol.taker;
import io.bitsquare.trade.Trade;
public interface TakerAsSellerProtocolListener
public interface ProtocolForTakerAsSellerListener
{
void onDepositTxPublished(String depositTxId);
@ -10,11 +10,11 @@ public interface TakerAsSellerProtocolListener
void onPayoutTxPublished(Trade trade, String hashAsString);
void onFault(Throwable throwable, TakerAsSellerProtocol.State state);
void onFault(Throwable throwable, ProtocolForTakerAsSeller.State state);
void onWaitingForPeerResponse(TakerAsSellerProtocol.State state);
void onWaitingForPeerResponse(ProtocolForTakerAsSeller.State state);
void onCompleted(TakerAsSellerProtocol.State state);
void onCompleted(ProtocolForTakerAsSeller.State state);
void onTakeOfferRequestRejected(Trade trade);
}

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.msg.TradeMessage;
@ -62,12 +62,12 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return offererTxOutIndex;
}
public BankAccount getBankAccount()
public BankAccount getTakerBankAccount()
{
return bankAccount;
}
public String getAccountId()
public String getTakerAccountId()
{
return accountID;
}
@ -92,7 +92,7 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return txConnOutAsHex;
}
public String getContractAsJson()
public String getTakerContractAsJson()
{
return contractAsJson;
}

View File

@ -1,10 +1,9 @@
package io.bitsquare.trade.protocol.tasks.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.taker.RequestTakeOfferMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;

View File

@ -1,11 +1,9 @@
package io.bitsquare.trade.protocol.tasks.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -14,9 +12,9 @@ public class SendPayoutTxToOfferer
{
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade trade, String payoutTxAsHex)
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, String tradeId, String payoutTxAsHex)
{
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(trade.getId(), payoutTxAsHex);
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{
@Override

View File

@ -0,0 +1,67 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendSignedTakerDepositTxAsHex
{
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
BankAccount bankAccount,
String accountId,
String messagePubKeyAsHex,
String tradeId,
String contractAsJson,
String takerSignature,
Transaction signedTakerDepositTx,
long offererTxOutIndex)
{
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(tradeId,
bankAccount,
accountId,
messagePubKeyAsHex,
Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1)
.getConnectedOutput()
.getParentTransaction()
.bitcoinSerialize()),
contractAsJson,
takerSignature,
walletFacade.getAddressInfoByTradeID(tradeId).getAddressString(),
takerTxOutIndex,
offererTxOutIndex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
resultHandler.onResult();
}
@Override
public void onFailed()
{
log.error("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer"));
}
});
}
}

View File

@ -1,10 +1,9 @@
package io.bitsquare.trade.protocol.tasks.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
@ -21,12 +20,9 @@ public class SendTakeOfferFeePayedTxId
String tradeId,
String takeOfferFeeTxId,
BigInteger tradeAmount,
String pubKeyAsHexString)
String pubKeyForThatTradeAsHex)
{
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId,
takeOfferFeeTxId,
tradeAmount,
pubKeyAsHexString);
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId, takeOfferFeeTxId, tradeAmount, pubKeyForThatTradeAsHex);
messageFacade.sendTradeMessage(peerAddress, msg, new OutgoingTradeMessageListener()
{

View File

@ -0,0 +1,66 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishPayoutTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
String tradeId,
String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererPayoutAddress)
{
try
{
walletFacade.takerSignsAndSendsTx(depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
tradeId,
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.debug("takerSignsAndSendsTx " + transaction);
String payoutTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
resultHandler.onResult(transaction.getHashAsString(), payoutTxAsHex);
}
@Override
public void onFailure(Throwable t)
{
log.error("Exception at takerSignsAndSendsTx " + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("Exception at takerSignsAndSendsTx " + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(String transactionId, String payoutTxAsHex);
}
}

View File

@ -1,4 +1,4 @@
package io.bitsquare.trade.protocol.messages.taker;
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.msg.TradeMessage;
import java.io.Serializable;
@ -11,14 +11,14 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage
private BigInteger tradeAmount;
private String takeOfferFeeTxID;
private String takerMultiSigPubKey;
private String takerPubKey;
public TakeOfferFeePayedMessage(String tradeId, String takeOfferFeeTxID, BigInteger tradeAmount, String takerMultiSigPubKey)
public TakeOfferFeePayedMessage(String tradeId, String takeOfferFeeTxID, BigInteger tradeAmount, String takerPubKey)
{
this.tradeId = tradeId;
this.takeOfferFeeTxID = takeOfferFeeTxID;
this.tradeAmount = tradeAmount;
this.takerMultiSigPubKey = takerMultiSigPubKey;
this.takerPubKey = takerPubKey;
}
@Override
@ -37,9 +37,9 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage
return takeOfferFeeTxID;
}
public String getTakerMultiSigPubKey()
public String getTakerPubKey()
{
return takerMultiSigPubKey;
return takerPubKey;
}
}

View File

@ -1,882 +0,0 @@
package io.bitsquare.trade.protocol.taker;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.messages.offerer.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.tasks.taker.*;
import io.bitsquare.user.User;
import java.math.BigInteger;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
import static io.bitsquare.util.Validator.nonNegativeLongOf;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer.
* That class handles the role of the taker as the Bitcoin seller.
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
*/
public class TakerAsSellerProtocol
{
private static final Logger log = LoggerFactory.getLogger(TakerAsSellerProtocol.class);
// provided data
private final Trade trade;
private final TakerAsSellerProtocolListener listener;
private final MessageFacade messageFacade;
private final WalletFacade walletFacade;
private final BlockChainFacade blockChainFacade;
private final CryptoFacade cryptoFacade;
private final User user;
private final String id;
private final Offer offer;
private final String tradeId;
// written/read by task
private String payoutTxAsHex;
private PeerAddress peerAddress;
private Transaction signedTakerDepositTx;
private long takerTxOutIndex;
// written by message, read by tasks
private String peersAccountId;
private BankAccount peersBankAccount;
private String offererPubKey;
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
private String depositTxAsHex;
private String offererSignatureR;
private String offererSignatureS;
private BigInteger offererPaybackAmount;
private BigInteger takerPaybackAmount;
private String offererPayoutAddress;
//private
private State state;
public TakerAsSellerProtocol(Trade trade,
TakerAsSellerProtocolListener listener,
MessageFacade messageFacade,
WalletFacade walletFacade,
BlockChainFacade blockChainFacade,
CryptoFacade cryptoFacade,
User user)
{
this.trade = trade;
this.listener = listener;
this.messageFacade = messageFacade;
this.walletFacade = walletFacade;
this.blockChainFacade = blockChainFacade;
this.cryptoFacade = cryptoFacade;
this.user = user;
offer = trade.getOffer();
tradeId = trade.getId();
id = trade.getId();
state = State.Init;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
public void onFault(Throwable throwable)
{
listener.onFault(throwable, state);
}
public void start()
{
String messagePubKeyAsHex = nonEmptyStringOf(offer.getMessagePubKeyAsHex());
GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, messageFacade, messagePubKeyAsHex);
state = State.GetPeerAddress;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultGetPeerAddress(PeerAddress peerAddress)
{
this.peerAddress = checkNotNull(peerAddress);
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, this.peerAddress, messageFacade, tradeId);
state = State.RequestTakeOffer;
}
public void onResultRequestTakeOffer()
{
listener.onWaitingForPeerResponse(state);
}
public void onAcceptTakeOfferRequestMessage()
{
log.debug("onAcceptTakeOfferRequestMessage");
checkState(state == State.RequestTakeOffer);
PayTakeOfferFee.run(this::onResultPayTakeOfferFee, this::onFault, walletFacade, tradeId);
state = State.PayTakeOfferFee;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// OR
public void onRejectTakeOfferRequestMessage()
{
log.debug("onRejectTakeOfferRequestMessage");
checkState(state == State.RequestTakeOffer);
state = State.onRejectTakeOfferRequestMessage;
listener.onTakeOfferRequestRejected(trade);
}
public void onResultPayTakeOfferFee(Transaction transaction)
{
checkNotNull(transaction);
String transactionId = nonEmptyStringOf(transaction.getHashAsString());
trade.setTakeOfferFeeTxID(transactionId);
String takeOfferFeeTxId = trade.getTakeOfferFeeTxId();
BigInteger tradeAmount = trade.getTradeAmount();
String pubKeyAsHexString = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
SendTakeOfferFeePayedTxId.run(this::onResultSendTakeOfferFeePayedTxId,
this::onFault,
peerAddress,
messageFacade,
tradeId,
takeOfferFeeTxId,
tradeAmount,
pubKeyAsHexString);
state = State.SendTakeOfferFeePayedTxId;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultSendTakeOfferFeePayedTxId()
{
listener.onWaitingForPeerResponse(state);
}
public void onRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage message)
{
log.debug("onRequestTakerDepositPaymentMessage");
checkState(state == State.SendTakeOfferFeePayedTxId);
peersAccountId = nonEmptyStringOf(message.getAccountID());
peersBankAccount = checkNotNull(message.getBankAccount());
offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
VerifyOffererAccount.run(this::onResultVerifyOffererAccount,
this::onFault,
blockChainFacade,
peersAccountId,
peersBankAccount);
state = State.VerifyOffererAccount;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultVerifyOffererAccount()
{
CreateAndSignContract.run(this::onResultCreateAndSignContract,
this::onFault,
cryptoFacade,
trade,
user,
peersAccountId,
peersBankAccount,
walletFacade.getRegistrationAddressInfo().getKey());
state = State.CreateAndSignContract;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultCreateAndSignContract()
{
PayDeposit.run(this::onResultPayDeposit, this::onFault, walletFacade, trade, offererPubKey, preparedOffererDepositTxAsHex);
state = State.PayDeposit;
}
public void onResultPayDeposit(Transaction signedTakerDepositTx, long takerTxOutIndex)
{
SendSignedTakerDepositTxAsHex.run(this::onResultSendSignedTakerDepositTxAsHex,
this::onFault,
peerAddress,
messageFacade,
walletFacade,
trade,
user,
signedTakerDepositTx,
takerTxOutIndex,
offererTxOutIndex);
state = State.SendSignedTakerDepositTxAsHex;
}
public void onResultSendSignedTakerDepositTxAsHex()
{
listener.onWaitingForPeerResponse(state);
}
// informational, does only trigger UI feedback/update
public void onDepositTxPublishedMessage(DepositTxPublishedMessage message)
{
log.debug("onDepositTxPublishedMessage");
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
{
state = State.onDepositTxPublishedMessage;
listener.onDepositTxPublished(walletFacade.takerCommitDepositTx(message.getDepositTxAsHex()));
}
else
{
log.error("Invalid state. Actual state is: " + state);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// informational, store data for later, does only trigger UI feedback/update
public void onBankTransferInitedMessage(BankTransferInitedMessage tradeMessage)
{
log.debug("onBankTransferInitedMessage");
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
{
state = State.onBankTransferInitedMessage;
depositTxAsHex = tradeMessage.getDepositTxAsHex();
offererSignatureR = tradeMessage.getOffererSignatureR();
offererSignatureS = tradeMessage.getOffererSignatureS();
offererPaybackAmount = tradeMessage.getOffererPaybackAmount();
takerPaybackAmount = tradeMessage.getTakerPaybackAmount();
offererPayoutAddress = tradeMessage.getOffererPayoutAddress();
listener.onBankTransferInited(tradeMessage.getTradeId());
}
else
{
log.error("Invalid state. Actual state is: " + state);
}
}
// User clicked the "bank transfer received" button, so we release the funds for pay out
public void onUIEventFiatReceived()
{
log.debug("onUIEventFiatReceived");
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
{
state = State.onUIEventFiatReceived;
SignAndPublishPayoutTx.run(this::onResultSignAndPublishPayoutTx,
this::onFault,
walletFacade,
trade,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
state = State.SignAndPublishPayoutTx;
}
else
{
log.error("Invalid state. Actual state is: " + state);
}
}
public void onResultSignAndPublishPayoutTx(Transaction transaction, String payoutTxAsHex)
{
listener.onPayoutTxPublished(trade, transaction.getHashAsString());
SendPayoutTxToOfferer.run(this::onResultSendPayoutTxToOfferer, this::onFault, peerAddress, messageFacade, trade, payoutTxAsHex);
state = State.SendPayoutTxToOfferer;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Tasks
///////////////////////////////////////////////////////////////////////////////////////////
public void onResultSendPayoutTxToOfferer()
{
checkState(state == State.SendPayoutTxToOfferer);
listener.onCompleted(state);
}
public String getId()
{
return id;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public enum State
{
Init,
GetPeerAddress,
RequestTakeOffer,
PayTakeOfferFee,
onRejectTakeOfferRequestMessage,
SendTakeOfferFeePayedTxId,
VerifyOffererAccount,
CreateAndSignContract,
PayDeposit,
SendSignedTakerDepositTxAsHex,
onDepositTxPublishedMessage,
onBankTransferInitedMessage,
onUIEventFiatReceived,
SignAndPublishPayoutTx,
SendPayoutTxToOfferer
}
///////////////////////////////////////////////////////////////////////////////////////////
// Step 1.1
///////////////////////////////////////////////////////////////////////////////////////////
/* private void findPeerAddress()
{
log.debug("1.1 findPeerAddress");
AddressLookupListener addressLookupListener = new AddressLookupListener()
{
@Override
public void onResult(PeerAddress address)
{
log.debug("1.1 findPeerAddress onResult");
// We got the peer address
peerAddress = address;
takerPaymentProtocolListener.onProgress(getProgress());
// next
requestTakeOffer();
}
@Override
public void onFailed()
{
log.debug("1.1 findPeerAddress onFailed");
takerPaymentProtocolListener.onFailure("onGetPeerAddressFailed");
}
};
takerPaymentProtocolListener.onProgress(getProgress());
// Request the peers address from the DHT
messageFacade.getPeerAddress(offer.getMessagePubKeyAsHex(), addressLookupListener);
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 1.2
///////////////////////////////////////////////////////////////////////////////////////////
/* private void requestTakeOffer()
{
log.debug("1.2 requestTakeOffer");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("1.2 requestTakeOffer onResult");
// Our message has arrived
// We don't know yet if the offerer has accepted
// the take request (if offer is not already reserved for another user)
// We await for an incoming message from the offerer with the accept msg
takerPaymentProtocolListener.onProgress(getProgress());
// Wait for message from offerer...
}
@Override
public void onFailed()
{
log.debug("1.2 requestTakeOffer onFailed");
takerPaymentProtocolListener.onFailure("sendTakeOfferRequest onSendTradingMessageFailed");
}
};
takerPaymentProtocolListener.onProgress(getProgress());
// Send the take offer request
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_TAKE_OFFER, trade.getId());
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
} */
//************************************************************************************************
// 1.3. Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 1.4
///////////////////////////////////////////////////////////////////////////////////////////
// 1.4a offerer has accepted the take offer request. Move on to step 2.
/* public void onAcceptTakeOfferRequestMessage()
{
log.debug("1.4a onAcceptTakeOfferRequestMessage");
// listener.onProgress(getProgress());
payOfferFee(trade);
}
// 1.4b Offerer has rejected the take offer request. The UI controller will onResult the case.
public void onRejectTakeOfferRequestMessage()
{
log.debug("1.4b onRejectTakeOfferRequestMessage");
// listener.onProgress(getProgress());
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.1
///////////////////////////////////////////////////////////////////////////////////////////
/* private void payOfferFee(Trade trade)
{
log.debug("2.1 payTakeOfferFee");
FutureCallback<Transaction> callback = new FutureCallback<Transaction>()
{
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{
log.debug("2.1 payTakeOfferFee onSuccess");
log.info("sendResult onSuccess txid:" + transaction.getHashAsString());
// Offer fee payed successfully.
trade.setTakeOfferFeeTxID(transaction.getHashAsString());
// listener.onProgress(getProgress());
// move on
sendTakerOfferFeeTxID(transaction.getHashAsString());
}
@Override
public void onFailure(Throwable t)
{
log.debug("2.1 payTakeOfferFee onFailure");
// listener.onFailure("payTakeOfferFee onFailure " + t.getMessage());
}
};
try
{
// Pay the offer fee
// listener.onProgress(getProgress());
walletFacade.payTakeOfferFee(trade.getId(), callback);
} catch (InsufficientMoneyException e)
{
// listener.onProgress(getProgress());
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.2
///////////////////////////////////////////////////////////////////////////////////////////
// Request peers account details. At that moment private data (bank account nr.) of the offerer get visible to the taker.
// We send also the tx id of the fee payment, so the offerer can confirm that the payment is seen in the network
// 0 block confirmation is acceptable for the fee to not block the process
// The offerer will wait until a minimum of peers seen the tx before sending his data.
// We also get the multisig tx delivered
/* private void sendTakerOfferFeeTxID(String takeOfferFeeTxID)
{
log.debug("2.2 sendTakerOfferFeeTxID");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("2.2 sendTakerOfferFeeTxID onResult");
// Message has arrived
//listener.onProgress(getProgress());
// We wait until the offerer send us the data
}
@Override
public void onFailed()
{
log.debug("2.2 sendTakerOfferFeeTxID onFailed");
// //TakerAsSellerProtocol.this. listener.onFailure("requestAccountDetails onSendTradingMessageFailed");
}
};
// this.listener.onProgress(getProgress());
// 2.3. send request for the account details and send fee tx id so offerer can verify that the fee has been paid.
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.TAKE_OFFER_FEE_PAYED,
trade.getId(),
trade.getTradeAmount(),
takeOfferFeeTxID,
walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString());
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
}
*/
//************************************************************************************************
// 2.3 - 2.6 Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.7 Incoming msg from offerer
///////////////////////////////////////////////////////////////////////////////////////////
/*public void onRequestTakerDepositPaymentMessage(TradeMessageOld requestTradeMessage)
{
log.debug("2.7 onRequestTakerDepositPaymentMessage");
verifyOfferer(requestTradeMessage);
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.8 Verify offerers account registration and against the blacklist
///////////////////////////////////////////////////////////////////////////////////////////
/*private void verifyOfferer(TradeMessageOld requestTradeMessage)
{
log.debug("2.8 verifyOfferer");
log.debug("2.8.1 verifyAccountRegistration");
if (blockChainFacade.verifyAccountRegistration())
{
log.debug("2.8.2 isAccountBlackListed");
if (blockChainFacade.isAccountBlackListed(requestTradeMessage.getAccountId(), requestTradeMessage.getBankAccount()))
{
// listener.onFailure("Offerer is blacklisted.");
}
else
{
createAndSignContract(requestTradeMessage);
}
}
else
{
// listener.onFailure("Offerers account registration is invalid.");
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.9 Create and sign the contract
///////////////////////////////////////////////////////////////////////////////////////////
/* private void createAndSignContract(TradeMessageOld requestTradeMessage)
{
log.debug("2.9 createAndSignContract");
checkNotNull(trade.getOffer());
checkNotNull(trade.getTradeAmount());
checkNotNull(trade.getTakeOfferFeeTxId());
checkNotNull(requestTradeMessage.getAccountId());
checkNotNull(user.getAccountId());
checkNotNull(requestTradeMessage.getBankAccount());
checkNotNull(user.getCurrentBankAccount());
checkNotNull(user.getMessagePubKeyAsHex());
Contract contract = new Contract(trade.getOffer(),
trade.getTradeAmount(),
trade.getTakeOfferFeeTxId(),
requestTradeMessage.getAccountId(),
user.getAccountId(),
requestTradeMessage.getBankAccount(),
user.getCurrentBankAccount(),
trade.getOffer().getMessagePubKeyAsHex(),
user.getMessagePubKeyAsHex()
);
log.debug("2.9 contract created: " + contract);
String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(walletFacade.getRegistrationAddressInfo().getKey(), contractAsJson);
//log.debug("2.9 contractAsJson: " + contractAsJson);
log.debug("2.9 contract signature: " + signature);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
payDeposit(requestTradeMessage);
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.10 Pay in the funds to the deposit tx and sign it
///////////////////////////////////////////////////////////////////////////////////////////
/*private void payDeposit(TradeMessageOld requestTradeMessage)
{
log.debug("2.10 payDeposit");
BigInteger collateralAmount = trade.getCollateralAmount();
BigInteger takerInputAmount = trade.getTradeAmount().add(collateralAmount);
BigInteger msOutputAmount = trade.getTradeAmount().add(collateralAmount).add(collateralAmount);
String offererPubKey = requestTradeMessage.getOffererPubKey();
String takerPubKey = walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
String arbitratorPubKey = trade.getOffer().getArbitrator().getPubKeyAsHex();
String preparedOffererDepositTxAsHex = requestTradeMessage.getPreparedOffererDepositTxAsHex();
checkNotNull(takerInputAmount);
checkNotNull(msOutputAmount);
checkNotNull(offererPubKey);
checkNotNull(takerPubKey);
checkNotNull(arbitratorPubKey);
checkNotNull(preparedOffererDepositTxAsHex);
log.debug("2.10 offererCreatesMSTxAndAddPayment");
log.debug("takerAmount " + BtcFormatter.formatSatoshis(takerInputAmount));
log.debug("msOutputAmount " + BtcFormatter.formatSatoshis(msOutputAmount));
log.debug("offerer pubkey " + offererPubKey);
log.debug("taker pubkey " + takerPubKey);
log.debug("arbitrator pubkey " + arbitratorPubKey);
log.debug("preparedOffererDepositTxAsHex " + preparedOffererDepositTxAsHex);
try
{
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(takerInputAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, preparedOffererDepositTxAsHex, trade.getId());
log.debug("2.10 deposit tx created: " + signedTakerDepositTx);
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
sendSignedTakerDepositTxAsHex(signedTakerDepositTx, takerTxOutIndex, requestTradeMessage.getOffererTxOutIndex());
} catch (InsufficientMoneyException e)
{
log.error("2.10 error at walletFacade.takerAddPaymentAndSign: " + e.getMessage());
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 2.11 Send the tx to the offerer
///////////////////////////////////////////////////////////////////////////////////////////
/* private void sendSignedTakerDepositTxAsHex(Transaction signedTakerDepositTx, long takerTxOutIndex, long offererTxOutIndex)
{
log.debug("2.11 sendSignedTakerDepositTxAsHex");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("2.11 sendSignedTakerDepositTxAsHex REQUEST_TAKER_DEPOSIT_PAYMENT onResult");
// Message arrived at taker
// //TakerAsSellerProtocol.this. listener.onFailure(getProgress());
}
@Override
public void onFailed()
{
log.debug("2.11 sendSignedTakerDepositTxAsHex REQUEST_TAKER_DEPOSIT_PAYMENT onFailed");
////TakerAsSellerProtocol.this. listener.onFailure("sendSignedTakerDepositTxAsHex REQUEST_TAKER_DEPOSIT_PAYMENT onFailed");
}
};
// this.listener.onProgress(getProgress());
BankAccount bankAccount = user.getCurrentBankAccount();
String accountID = user.getAccountId();
String messagePubKey = user.getMessagePubKeyAsHex();
String contractAsJson = trade.getContractAsJson();
String signature = trade.getTakerSignature();
String signedTakerDepositTxAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize());
String txScriptSigAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes());
String txConnOutAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize());
//TODO just 1 address supported yet
String payoutAddress = walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString();
log.debug("2.10 deposit txAsHex: " + signedTakerDepositTxAsHex);
log.debug("2.10 txScriptSigAsHex: " + txScriptSigAsHex);
log.debug("2.10 txConnOutAsHex: " + txConnOutAsHex);
log.debug("2.10 payoutAddress: " + payoutAddress);
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.REQUEST_OFFERER_DEPOSIT_PUBLICATION,
trade.getId(),
bankAccount,
accountID,
messagePubKey,
signedTakerDepositTxAsHex,
txScriptSigAsHex,
txConnOutAsHex,
contractAsJson,
signature,
payoutAddress,
takerTxOutIndex,
offererTxOutIndex
);
log.debug("2.11 sendTradingMessage");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
} */
//************************************************************************************************
// 3.1 - 3.5 Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.6 Incoming msg from offerer
///////////////////////////////////////////////////////////////////////////////////////////
/* public void onDepositTxPublishedMessage(TradeMessageOld tradeMessage)
{
log.debug("3.6 DepositTxID received: " + tradeMessage.getDepositTxAsHex());
String txID = walletFacade.takerCommitDepositTx(tradeMessage.getDepositTxAsHex());
// listener.onProgress(getProgress());
listener.onDepositTxPublishedMessage(txID);
} */
//************************************************************************************************
// 3.7-3.10 Offerers tasks, we are in waiting mode
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.11 Incoming msg from offerer
///////////////////////////////////////////////////////////////////////////////////////////
/* public void onBankTransferInitedMessage(BankTransferInitedMessage tradeMessage)
{
log.debug("3.11 Bank transfer inited msg received");
listener.onBankTransferInitedMessage(tradeMessage);
} */
//************************************************************************************************
// Taker will check periodically his bank account until he received the money. That might take a while...
//************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.12 User clicked the "bank transfer received" button, so we release the funds for pay out
///////////////////////////////////////////////////////////////////////////////////////////
/* public void onUIEventFiatReceived(TradeMessageOld tradeMessage)
{
log.debug("3.12 onUIEventFiatReceived");
FutureCallback<Transaction> callback = new FutureCallback<Transaction>()
{
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction)
{
System.out.println("######### 3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
log.debug("3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
listener.onPayoutTxPublished(transaction.getHashAsString());
sendPayoutTxToOfferer(Utils.bytesToHexString(transaction.bitcoinSerialize()));
}
@Override
public void onFailure(Throwable t)
{
log.error("######### 3.12 onFailure walletFacade.takerSignsAndSendsTx");
System.err.println("3.12 onFailure walletFacade.takerSignsAndSendsTx");
// listener.onFailure("takerSignsAndSendsTx failed " + t.getMessage());
}
};
try
{
String depositTxAsHex = tradeMessage.getDepositTxAsHex();
String offererSignatureR = tradeMessage.getOffererSignatureR();
String offererSignatureS = tradeMessage.getOffererSignatureS();
BigInteger offererPaybackAmount = tradeMessage.getOffererPaybackAmount();
BigInteger takerPaybackAmount = tradeMessage.getTakerPaybackAmount();
String offererPayoutAddress = tradeMessage.getOffererPayoutAddress();
log.debug("3.12 walletFacade.takerSignsAndSendsTx");
walletFacade.takerSignsAndSendsTx(depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
trade.getId(),
callback);
} catch (AddressFormatException e)
{
log.error("3.12 offererCreatesAndSignsPayoutTx onFailed AddressFormatException " + e.getMessage());
}
} */
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.13 Send payout txID to offerer
///////////////////////////////////////////////////////////////////////////////////////////
/*void sendPayoutTxToOfferer(String payoutTxAsHex)
{
log.debug("3.13 sendPayoutTxToOfferer ");
TradeMessageListener listener = new TradeMessageListener()
{
@Override
public void onResult()
{
log.debug("3.13 sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onResult");
log.debug("3.13 TRADE COMPLETE!!!!!!!!!!!");
//TakerAsSellerProtocol.this. listener.onFailure(getProgress());
}
@Override
public void onFailed()
{
log.debug("3.13 sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onFailed");
//TakerAsSellerProtocol.this. listener.onFailure("sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onFailed");
}
};
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.PAYOUT_TX_PUBLISHED, trade.getId());
tradeMessage.setPayoutTxAsHex(payoutTxAsHex);
log.debug("3.13 sendTradeMessage PAYOUT_TX_PUBLISHED");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
} */
/* private double getProgress()
{
currentStep++;
int numberOfSteps = 10;
return (double) currentStep / (double) numberOfSteps;
} */
}

View File

@ -0,0 +1,19 @@
package io.bitsquare.trade.protocol.taker;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.FaultHandler;
import io.bitsquare.trade.protocol.ResultHandler;
import io.bitsquare.trade.protocol.shared.VerifyPeerAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyOffererAccount
{
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{
VerifyPeerAccount.run(resultHandler, faultHandler, blockChainFacade, peersAccountId, peersBankAccount);
}
}

View File

@ -1,65 +0,0 @@
package io.bitsquare.trade.protocol.tasks.offerer;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.offerer.AcceptTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.messages.offerer.RejectTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HandleTakeOfferRequest
{
private static final Logger log = LoggerFactory.getLogger(HandleTakeOfferRequest.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade.State tradeState, String tradeId)
{
if (tradeState == Trade.State.OPEN)
{
messageFacade.sendTradeMessage(peerAddress, new AcceptTakeOfferRequestMessage(tradeId), new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("AcceptTakeOfferRequestMessage successfully arrived at peer");
resultHandler.onResult(Trade.State.ACCEPTED);
}
@Override
public void onFailed()
{
log.error("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer"));
}
});
}
else
{
RejectTakeOfferRequestMessage msg = new RejectTakeOfferRequestMessage(tradeId);
messageFacade.sendTradeMessage(peerAddress, msg, new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RejectTakeOfferRequestMessage successfully arrived at peer");
}
@Override
public void onFailed()
{
log.error("RejectTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
}
});
log.error("Offer not marked as open.");
faultHandler.onFault(new Exception("Offer not marked as open."));
}
}
public interface ResultHandler
{
void onResult(Trade.State tradeState);
}
}

View File

@ -1,40 +0,0 @@
package io.bitsquare.trade.protocol.tasks.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence;
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocolListener;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SetupListenerForBlockChainConfirmation
{
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, Transaction depositTransaction, OffererAsBuyerProtocolListener listener)
{ //TODO
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().addEventListener(new TransactionConfidence.Listener()
{
@Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason)
{
log.trace("onConfidenceChanged " + tx.getConfidence());
if (reason == ChangeReason.SEEN_PEERS)
{
listener.onDepositTxConfirmedUpdate(tx.getConfidence());
}
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
{
listener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().removeEventListener(this);
log.trace("Tx is in blockchain");
resultHandler.onResult();
}
}
}
);
}
}

View File

@ -1,60 +0,0 @@
package io.bitsquare.trade.protocol.tasks.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishDepositTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
String preparedOffererDepositTxAsHex,
String signedTakerDepositTxAsHex,
String txConnOutAsHex,
String txScriptSigAsHex,
long offererTxOutIndex,
long takerTxOutIndex)
{
try
{
walletFacade.offererSignAndPublishTx(preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex,
txConnOutAsHex,
txScriptSigAsHex,
offererTxOutIndex,
takerTxOutIndex,
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.trace("offererSignAndPublishTx succeeded " + transaction);
resultHandler.onResult(transaction);
}
@Override
public void onFailure(Throwable t)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("offererSignAndPublishTx faultHandler.onFault:" + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(Transaction transaction);
}
}

View File

@ -1,60 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.ECKey;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.user.User;
import io.bitsquare.util.Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateAndSignContract
{
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
CryptoFacade cryptoFacade,
Trade trade,
User user,
String peersAccountId,
BankAccount peersBankAccount,
ECKey registrationKey)
{
try
{
Contract contract = new Contract(trade.getOffer(),
trade.getTradeAmount(),
trade.getTakeOfferFeeTxId(),
peersAccountId,
user.getAccountId(),
peersBankAccount,
user.getCurrentBankAccount(),
trade.getOffer().getMessagePubKeyAsHex(),
user.getMessagePubKeyAsHex()
);
String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
//log.trace("contract: " + contract);
//log.debug("contractAsJson: " + contractAsJson);
//log.trace("contract signature: " + signature);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
resultHandler.onResult();
} catch (Throwable t)
{
log.error("Exception at sign contract " + t);
faultHandler.onFault(t);
}
}
}

View File

@ -1,46 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayDeposit
{
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, WalletFacade walletFacade, Trade trade, String offererPubKey, String preparedOffererDepositTxAsHex)
{
try
{
BigInteger collateralAmount = trade.getCollateralAmount();
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(trade.getTradeAmount().add(collateralAmount),
trade.getTradeAmount().add(collateralAmount).add(collateralAmount),
offererPubKey,
walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString(),
trade.getOffer().getArbitrator().getPubKeyAsHex(),
preparedOffererDepositTxAsHex,
trade.getId());
log.trace("sharedModel.signedTakerDepositTx: " + signedTakerDepositTx);
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
resultHandler.onResult(signedTakerDepositTx, takerTxOutIndex);
} catch (InsufficientMoneyException e)
{
log.error("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e);
faultHandler.onFault(new Exception("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e));
}
}
public interface ResultHandler
{
void onResult(Transaction signedTakerDepositTx, long takerTxOutIndex);
}
}

View File

@ -1,61 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import io.bitsquare.user.User;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendSignedTakerDepositTxAsHex
{
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
PeerAddress peerAddress,
MessageFacade messageFacade,
WalletFacade walletFacade,
Trade trade,
User user,
Transaction signedTakerDepositTx,
long takerTxOutIndex,
long offererTxOutIndex)
{
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(trade.getId(),
user.getCurrentBankAccount(),
user.getAccountId(),
user.getMessagePubKeyAsHex(),
Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes()),
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize()),
trade.getContractAsJson(),
trade.getTakerSignature(),
walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString(),
takerTxOutIndex,
offererTxOutIndex);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{
@Override
public void onResult()
{
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
resultHandler.onResult();
}
@Override
public void onFailed()
{
log.error("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer");
faultHandler.onFault(new Exception("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer"));
}
});
}
}

View File

@ -1,68 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignAndPublishPayoutTx
{
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
public static void run(ResultHandler resultHandler,
FaultHandler faultHandler,
WalletFacade walletFacade,
Trade trade,
String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererPayoutAddress
)
{
try
{
walletFacade.takerSignsAndSendsTx(depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
trade.getId(),
new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.debug("takerSignsAndSendsTx " + transaction);
String payoutTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
resultHandler.onResult(transaction, payoutTxAsHex);
}
@Override
public void onFailure(Throwable t)
{
log.error("Exception at takerSignsAndSendsTx " + t);
faultHandler.onFault(t);
}
});
} catch (Exception e)
{
log.error("Exception at takerSignsAndSendsTx " + e);
faultHandler.onFault(e);
}
}
public interface ResultHandler
{
void onResult(Transaction transaction, String payoutTxAsHex);
}
}

View File

@ -1,35 +0,0 @@
package io.bitsquare.trade.protocol.tasks.taker;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyOffererAccount
{
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
{
//TODO mocked yet
if (blockChainFacade.verifyAccountRegistration())
{
if (blockChainFacade.isAccountBlackListed(peersAccountId, peersBankAccount))
{
log.error("Offerer is blacklisted");
faultHandler.onFault(new Exception("Offerer is blacklisted"));
}
else
{
resultHandler.onResult();
}
}
else
{
log.error("Account Registration for peer faultHandler.onFault.");
faultHandler.onFault(new Exception("Account Registration for peer faultHandler.onFault."));
}
}
}

View File

@ -94,18 +94,26 @@ public class Arbitrator implements Serializable
public int hashCode()
{
if (id != null)
{
return Objects.hashCode(id);
}
else
{
return 0;
}
}
@SuppressWarnings("NonFinalFieldReferenceInEquals")
public boolean equals(Object obj)
{
if (!(obj instanceof Arbitrator))
{
return false;
}
if (obj == this)
{
return true;
}
Arbitrator other = (Arbitrator) obj;
return id != null && id.equals(other.getId());

View File

@ -46,17 +46,28 @@ public class User implements Serializable
public void addBankAccount(BankAccount bankAccount)
{
if (!bankAccounts.contains(bankAccount))
{
bankAccounts.add(bankAccount);
}
currentBankAccount = bankAccount;
}
public void removeCurrentBankAccount()
{
if (currentBankAccount != null) bankAccounts.remove(currentBankAccount);
if (currentBankAccount != null)
{
bankAccounts.remove(currentBankAccount);
}
if (bankAccounts.isEmpty()) currentBankAccount = null;
else currentBankAccount = bankAccounts.get(0);
if (bankAccounts.isEmpty())
{
currentBankAccount = null;
}
else
{
currentBankAccount = bankAccounts.get(0);
}
}
@ -74,7 +85,9 @@ public class User implements Serializable
bankAccountUIDs += bankAccount.toString();
if (i < bankAccounts.size() - 1)
{
bankAccountUIDs += ", ";
}
}
return bankAccountUIDs;
@ -136,7 +149,9 @@ public class User implements Serializable
for (final BankAccount bankAccount : bankAccounts)
{
if (bankAccount.getUid().equals(bankAccountId))
{
return bankAccount;
}
}
return null;
}

View File

@ -60,9 +60,13 @@ public class DSAKeyUtil
} catch (Throwable throwable)
{
if (throwable instanceof FileNotFoundException)
{
log.debug("Files not found. That is ok for the first execute.");
}
else
{
log.error("Could not read key files. " + throwable);
}
try
{
@ -114,15 +118,23 @@ public class DSAKeyUtil
// Work around an issue on Windows whereby you can't rename over existing files.
final File pubKeyCanonicalFile = pubKeyFile.getCanonicalFile();
if (pubKeyCanonicalFile.exists() && !pubKeyCanonicalFile.delete())
{
throw new IOException("Failed to delete pubKeyCanonicalFile for replacement with save");
}
if (!pubKeyTempFile.renameTo(pubKeyCanonicalFile))
{
throw new IOException("Failed to rename " + pubKeyTempFile + " to " + pubKeyCanonicalFile);
}
final File privKeyCanonicalFile = privKeyFile.getCanonicalFile();
if (privKeyCanonicalFile.exists() && !privKeyCanonicalFile.delete())
{
throw new IOException("Failed to delete privKeyCanonicalFile for replacement with save");
}
if (!privKeyTempFile.renameTo(privKeyCanonicalFile))
{
throw new IOException("Failed to rename " + privKeyTempFile + " to " + privKeyCanonicalFile);
}
}
else
{
@ -141,13 +153,17 @@ public class DSAKeyUtil
{
log.warn("PubKeyTempFile still exists after failed save.");
if (!pubKeyTempFile.delete())
{
log.warn("Cannot delete pubKeyTempFile.");
}
}
if (privKeyTempFile.exists())
{
log.warn("PrivKeyTempFile still exists after failed save.");
if (!privKeyTempFile.delete())
{
log.warn("Cannot delete privKeyTempFile.");
}
}
lock.unlock();

View File

@ -33,7 +33,9 @@ public class FileUtil
if (!dir.exists())
{
if (!dir.mkdir())
{
log.error("Could not create directory. " + dir.getAbsolutePath());
}
}
return dir;

View File

@ -82,7 +82,9 @@ public class Utilities
private static void printElapsedTime(String msg)
{
if (!msg.isEmpty())
{
msg += " / ";
}
long timeStamp = System.currentTimeMillis();
log.debug(msg + "Elapsed: " + String.valueOf(timeStamp - lastTimeStamp));
lastTimeStamp = timeStamp;