mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-04-19 07:15:54 -04:00
refactoring trade protocol, reformatting
This commit is contained in:
parent
cb4ca6b2a7
commit
fd1f23ea62
13
pom.xml
13
pom.xml
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,9 @@ public class GuiceFXMLLoader extends FXMLLoader
|
||||
private void setupControllerFactory()
|
||||
{
|
||||
if (GuiceFXMLLoader.injector != null)
|
||||
{
|
||||
setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -37,7 +37,9 @@ public class ProcessStepBar<T> extends Control
|
||||
{
|
||||
this.processStepItems = processStepItems;
|
||||
if (getSkin() != null)
|
||||
{
|
||||
((ProcessStepBarSkin) getSkin()).dataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void next()
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.bitsquare.trade.protocol.tasks;
|
||||
package io.bitsquare.trade.protocol;
|
||||
|
||||
public interface FaultHandler
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
package io.bitsquare.trade.protocol.tasks;
|
||||
package io.bitsquare.trade.protocol;
|
||||
|
||||
public interface ResultHandler
|
||||
{
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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,
|
@ -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();
|
@ -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;
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
@ -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()
|
||||
{
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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
|
@ -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;
|
@ -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
|
@ -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
|
@ -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)
|
||||
{
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
@ -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;
|
@ -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
|
@ -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"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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()
|
||||
{
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
} */
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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."));
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -33,7 +33,9 @@ public class FileUtil
|
||||
if (!dir.exists())
|
||||
{
|
||||
if (!dir.mkdir())
|
||||
{
|
||||
log.error("Could not create directory. " + dir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user