payment process payout done

This commit is contained in:
Manfred Karrer 2014-05-17 01:48:23 +02:00
parent 9af3f6aeba
commit a508f95582
28 changed files with 867 additions and 377 deletions

View file

@ -122,13 +122,13 @@ public class BitSquare extends Application
settings.getAcceptedArbitrators().clear(); settings.getAcceptedArbitrators().clear();
settings.addAcceptedArbitrator(new Arbitrator("uid_1", "Charlie Boom", Utils.bytesToHexString(new ECKey().getPubKey()), settings.addAcceptedArbitrator(new Arbitrator("uid_1", "Charlie Boom", Utils.bytesToHexString(new ECKey().getPubKey()),
getMessagePubKey(), "http://www.arbit.io/Charly_Boom", 1, 10, Utils.toNanoCoins("0.01"))); getMessagePubKey(), "http://www.arbit.io/Charly_Boom", 10, 50, Utils.toNanoCoins("0.01")));
settings.addAcceptedArbitrator(new Arbitrator("uid_2", "Tom Shang", Utils.bytesToHexString(new ECKey().getPubKey()), settings.addAcceptedArbitrator(new Arbitrator("uid_2", "Tom Shang", Utils.bytesToHexString(new ECKey().getPubKey()),
getMessagePubKey(), "http://www.arbit.io/Tom_Shang", 0, 1, Utils.toNanoCoins("0.001"))); getMessagePubKey(), "http://www.arbit.io/Tom_Shang", 10, 100, Utils.toNanoCoins("0.001")));
settings.addAcceptedArbitrator(new Arbitrator("uid_3", "Edward Snow", Utils.bytesToHexString(new ECKey().getPubKey()), settings.addAcceptedArbitrator(new Arbitrator("uid_3", "Edward Snow", Utils.bytesToHexString(new ECKey().getPubKey()),
getMessagePubKey(), "http://www.arbit.io/Edward_Swow", 2, 5, Utils.toNanoCoins("0.05"))); getMessagePubKey(), "http://www.arbit.io/Edward_Swow", 20, 50, Utils.toNanoCoins("0.05")));
settings.addAcceptedArbitrator(new Arbitrator("uid_4", "Julian Sander", Utils.bytesToHexString(new ECKey().getPubKey()), settings.addAcceptedArbitrator(new Arbitrator("uid_4", "Julian Sander", Utils.bytesToHexString(new ECKey().getPubKey()),
getMessagePubKey(), "http://www.arbit.io/Julian_Sander", 0, 20, Utils.toNanoCoins("0.1"))); getMessagePubKey(), "http://www.arbit.io/Julian_Sander", 10, 20, Utils.toNanoCoins("0.1")));
settings.setMinCollateral(1); settings.setMinCollateral(1);
settings.setMaxCollateral(10); settings.setMaxCollateral(10);

View file

@ -23,7 +23,7 @@ public class RelayNode
{ {
masterPeer = new PeerMaker(ID).setPorts(port).makeAndListen(); masterPeer = new PeerMaker(ID).setPorts(port).makeAndListen();
// masterPeer = new PeerMaker(ID).setPorts(port).setBagSize(100).makeAndListen(); // setBagSize cause sync problems... // masterPeer = new PeerMaker(ID).setPorts(port).setBagSize(100).makeAndListen(); // setBagSize cause sync problems...
masterPeer.getBroadcastRPC().getConnectionBean().getConnectionReservation().reserve(10).awaitUninterruptibly(); masterPeer.getBroadcastRPC().getConnectionBean().getConnectionReservation().reserve(3).awaitUninterruptibly();
} }
return masterPeer; return masterPeer;
} }

View file

@ -9,8 +9,6 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import io.bitsquare.BitSquare; import io.bitsquare.BitSquare;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -25,23 +23,33 @@ import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
public class AccountRegistrationWallet extends Wallet implements WalletEventListener public class AccountRegistrationWallet extends Wallet implements WalletEventListener
{ {
private static final Logger log = LoggerFactory.getLogger(AccountRegistrationWallet.class); // private static final Logger log = LoggerFactory.getLogger(AccountRegistrationWallet.class);
private final File walletFile; private final File walletFile;
private NetworkParameters networkParameters; private NetworkParameters params;
private BlockChain chain; private BlockChain chain;
private PeerGroup peerGroup; private PeerGroup peerGroup;
private List<WalletFacade.WalletListener> walletListeners = new ArrayList<>(); private List<WalletFacade.WalletListener> walletListeners = new ArrayList<>();
AccountRegistrationWallet(NetworkParameters networkParameters, BlockChain chain, PeerGroup peerGroup) AccountRegistrationWallet(NetworkParameters params, BlockChain chain, PeerGroup peerGroup)
{ {
super(networkParameters); super(params);
this.networkParameters = networkParameters; this.params = params;
this.chain = chain; this.chain = chain;
this.peerGroup = peerGroup; this.peerGroup = peerGroup;
walletFile = new File(Utilities.getRootDir() + "account_reg_" + BitSquare.ID + ".wallet"); /* try
{
final InetAddress localHost = InetAddress.getLocalHost();
PeerAddress peerAddress = new PeerAddress(localHost, params.getPort());
peerGroup.addAddress(peerAddress);
} catch (UnknownHostException e)
{
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} */
walletFile = new File(Utilities.getRootDir() + BitSquare.ID + "_account_reg" + ".wallet");
if (walletFile.exists()) if (walletFile.exists())
{ {
FileInputStream walletStream = null; FileInputStream walletStream = null;
@ -78,6 +86,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
} }
autosaveToFile(walletFile, 1, TimeUnit.SECONDS, null); autosaveToFile(walletFile, 1, TimeUnit.SECONDS, null);
peerGroup.setMinBroadcastConnections(1);
allowSpendingUnconfirmedTransactions(); allowSpendingUnconfirmedTransactions();
} }
@ -95,7 +104,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
Address getAddress() Address getAddress()
{ {
return getKey().toAddress(networkParameters); return getKey().toAddress(params);
} }
ECKey getKey() ECKey getKey()
@ -125,8 +134,8 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
.op(OP_RETURN) .op(OP_RETURN)
.data(dataToEmbed) .data(dataToEmbed)
.build(); .build();
Transaction transaction = new Transaction(networkParameters); Transaction transaction = new Transaction(params);
TransactionOutput dataOutput = new TransactionOutput(networkParameters, TransactionOutput dataOutput = new TransactionOutput(params,
transaction, transaction,
Transaction.MIN_NONDUST_OUTPUT, Transaction.MIN_NONDUST_OUTPUT,
script.getProgram()); script.getProgram());
@ -144,14 +153,14 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
@Override @Override
public void onSuccess(Transaction result) public void onSuccess(Transaction result)
{ {
log.info("sendResult onSuccess:" + result.toString()); //log.info("sendResult onSuccess:" + result.toString());
// Platform.runLater(overlayUi::done); // Platform.runLater(overlayUi::done);
} }
@Override @Override
public void onFailure(Throwable t) public void onFailure(Throwable t)
{ {
log.warn("sendResult onFailure:" + t.toString()); //log.warn("sendResult onFailure:" + t.toString());
// We died trying to empty the wallet. // We died trying to empty the wallet.
// crashAlert(t); // crashAlert(t);
} }
@ -171,7 +180,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
for (WalletFacade.WalletListener walletListener : walletListeners) for (WalletFacade.WalletListener walletListener : walletListeners)
walletListener.onCoinsReceived(newBalance); walletListener.onCoinsReceived(newBalance);
// log.info("onCoinsReceived"); // //log.info("onCoinsReceived");
} }
@Override @Override
@ -180,37 +189,37 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
for (WalletFacade.WalletListener walletListener : walletListeners) for (WalletFacade.WalletListener walletListener : walletListeners)
walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(this)); walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(this));
// log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString()); // //log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString());
} }
@Override @Override
public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{ {
log.info("onCoinsSent"); //log.info("onCoinsSent");
} }
@Override @Override
public void onReorganize(Wallet wallet) public void onReorganize(Wallet wallet)
{ {
log.info("onReorganize"); //log.info("onReorganize");
} }
@Override @Override
public void onWalletChanged(Wallet wallet) public void onWalletChanged(Wallet wallet)
{ {
// log.info("onWalletChanged"); // //log.info("onWalletChanged");
} }
@Override @Override
public void onKeysAdded(Wallet wallet, List<ECKey> keys) public void onKeysAdded(Wallet wallet, List<ECKey> keys)
{ {
log.info("onKeysAdded"); //log.info("onKeysAdded");
} }
@Override @Override
public void onScriptsAdded(Wallet wallet, List<Script> scripts) public void onScriptsAdded(Wallet wallet, List<Script> scripts)
{ {
log.info("onScriptsAdded"); //log.info("onScriptsAdded");
} }
int getConfNumBroadcastPeers() int getConfNumBroadcastPeers()

View file

@ -1,14 +1,15 @@
package io.bitsquare.btc; package io.bitsquare.btc;
import com.google.bitcoin.core.Transaction; import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import java.math.BigInteger; import java.math.BigInteger;
public class Fees public class Fees
{ {
// min dust value lead to exception at for non standard to address pay scripts, so we use a value >= 7860 instead // min dust value lead to exception at for non standard to address pay scripts, so we use a value >= 7860 instead
public static BigInteger MS_TX_FEE = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; // Transaction.REFERENCE_DEFAULT_MIN_TX_FEE = BigInteger.valueOf(10000) public static BigInteger MS_TX_FEE = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
public static BigInteger ACCOUNT_REGISTRATION_FEE = BigInteger.valueOf(7860);// Utils.toNanoCoins("0.001"); public static BigInteger ACCOUNT_REGISTRATION_FEE = Utils.toNanoCoins("0.01").subtract(Transaction.MIN_NONDUST_OUTPUT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
public static BigInteger OFFER_CREATION_FEE = BigInteger.valueOf(7860); // Transaction.MIN_NONDUST_OUTPUT; // Utils.toNanoCoins("0.001"); public static BigInteger OFFER_CREATION_FEE = Utils.toNanoCoins("0.001").subtract(Transaction.MIN_NONDUST_OUTPUT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
public static BigInteger OFFER_TAKER_FEE = BigInteger.valueOf(7860); public static BigInteger OFFER_TAKER_FEE = OFFER_CREATION_FEE;
} }

View file

@ -15,7 +15,6 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.BitSquare; import io.bitsquare.BitSquare;
import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.gui.util.Popups;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.util.Pair; import javafx.util.Pair;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -27,6 +26,8 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
/** /**
* That facade delivers wallet functionality from the bitcoinJ library * That facade delivers wallet functionality from the bitcoinJ library
* Code from BitcoinJ must not be used outside that facade. * Code from BitcoinJ must not be used outside that facade.
@ -51,13 +52,15 @@ public class WalletFacade implements WalletEventListener
private CryptoFacade cryptoFacade; private CryptoFacade cryptoFacade;
// that wallet is used only for the registration process // that wallet is used only for the registration process
private AccountRegistrationWallet accountRegistrationWallet = null; //private AccountRegistrationWallet accountRegistrationWallet = null;
private List<DownloadListener> downloadListeners = new ArrayList<>(); private List<DownloadListener> downloadListeners = new ArrayList<>();
private List<WalletListener> walletListeners = new ArrayList<>(); private List<WalletListener> walletListeners = new ArrayList<>();
private Wallet wallet; private Wallet wallet;
private ECKey registrationKey;
private ECKey tradingKey;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -98,20 +101,27 @@ public class WalletFacade implements WalletEventListener
walletAppKit.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints")); walletAppKit.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints"));
} }
walletAppKit.setAutoSave(true);
// Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen // Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen
// or progress widget to keep the user engaged whilst we initialise, but we don't. // or progress widget to keep the user engaged whilst we initialise, but we don't.
walletAppKit.setDownloadListener(new BlockChainDownloadListener()) walletAppKit.setDownloadListener(new BlockChainDownloadListener()).setBlockingStartup(false).setUserAgent("BitSquare", "0.1");
.setBlockingStartup(false)
.setUserAgent("BitSquare", "0.1");
walletAppKit.startAsync(); walletAppKit.startAsync();
walletAppKit.awaitRunning(); walletAppKit.awaitRunning();
wallet = walletAppKit.wallet(); wallet = walletAppKit.wallet();
registrationKey = wallet.getKeys().get(0);
tradingKey = new ECKey();
wallet.addKey(tradingKey);
log.info("getConnectedPeers " + walletAppKit.peerGroup().getConnectedPeers().size());
wallet.allowSpendingUnconfirmedTransactions(); wallet.allowSpendingUnconfirmedTransactions();
walletAppKit.peerGroup().setMaxConnections(20); // walletAppKit.peerGroup().setMaxConnections(10);
walletAppKit.peerGroup().setMinBroadcastConnections(1);
wallet.addEventListener(this); wallet.addEventListener(this);
wallet.addWatchedAddress(tradingKey.toAddress(params));
// testTradeProcessDepositTx(); // testTradeProcessDepositTx();
// testTradeProcessPayOutTx(); // testTradeProcessPayOutTx();
@ -119,12 +129,17 @@ public class WalletFacade implements WalletEventListener
public void shutDown() public void shutDown()
{ {
if (accountRegistrationWallet != null) /*if (accountRegistrationWallet != null)
accountRegistrationWallet.shutDown(); accountRegistrationWallet.shutDown(); */
walletAppKit.stopAsync(); walletAppKit.stopAsync();
walletAppKit.awaitTerminated(); walletAppKit.awaitTerminated();
} }
public void updateWallet()
{
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Listener // Listener
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -139,7 +154,7 @@ public class WalletFacade implements WalletEventListener
downloadListeners.remove(listener); downloadListeners.remove(listener);
} }
public void addWalletListener(WalletListener listener) /* public void addWalletListener(WalletListener listener)
{ {
walletListeners.add(listener); walletListeners.add(listener);
} }
@ -157,7 +172,7 @@ public class WalletFacade implements WalletEventListener
public void removeRegistrationWalletListener(WalletListener listener) public void removeRegistrationWalletListener(WalletListener listener)
{ {
getAccountRegistrationWallet().removeWalletListener(listener); getAccountRegistrationWallet().removeWalletListener(listener);
} } */
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -171,10 +186,10 @@ public class WalletFacade implements WalletEventListener
public String getAddressAsString() public String getAddressAsString()
{ {
return wallet.getKeys().get(0).toAddress(params).toString(); return tradingKey.toAddress(params).toString();
} }
public String payFee(BigInteger fee, FutureCallback<Transaction> callback) throws InsufficientMoneyException public String payOfferFee(BigInteger fee, FutureCallback<Transaction> callback) throws InsufficientMoneyException
{ {
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
//TransactionOutput output = new TransactionOutput(params, tx, Transaction.MIN_NONDUST_OUTPUT, WalletUtil.getEmptyOP_RETURNScript()); //TransactionOutput output = new TransactionOutput(params, tx, Transaction.MIN_NONDUST_OUTPUT, WalletUtil.getEmptyOP_RETURNScript());
@ -206,36 +221,84 @@ public class WalletFacade implements WalletEventListener
// Account registration // Account registration
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public Address getAccountRegistrationAddress() public Address getAccountRegistrationAddress()
{ {
return getAccountRegistrationWallet().getAddress(); return registrationKey.toAddress(params);
} }
public String getAccountRegistrationPubKey() /* public String getAccountRegistrationPubKey()
{ {
return Utils.bytesToHexString(getAccountRegistrationKey().getPubKey()); return Utils.bytesToHexString(getAccountRegistrationKey().getPubKey());
} } */
public BigInteger getAccountRegistrationBalance() public BigInteger getAccountRegistrationBalance()
{ {
return getAccountRegistrationWallet().getBalance(Wallet.BalanceType.ESTIMATED); return wallet.getBalance(Wallet.BalanceType.ESTIMATED);
// return getAccountRegistrationWallet().getBalance(Wallet.BalanceType.ESTIMATED);
} }
public void sendRegistrationTx(String stringifiedBankAccounts) throws InsufficientMoneyException public void sendRegistrationTx(String stringifiedBankAccounts) throws InsufficientMoneyException
{ {
getAccountRegistrationWallet().saveToBlockchain(cryptoFacade.getEmbeddedAccountRegistrationData(getAccountRegistrationWallet().getKey(), stringifiedBankAccounts)); saveToBlockchain(cryptoFacade.getEmbeddedAccountRegistrationData(registrationKey, stringifiedBankAccounts));
} }
public ECKey getAccountRegistrationKey() public ECKey getRegistrationKey()
{ {
return getAccountRegistrationWallet().getKey(); return registrationKey;
} }
void saveToBlockchain(byte[] dataToEmbed) throws InsufficientMoneyException
{
Script script = new ScriptBuilder()
.op(OP_RETURN)
.data(dataToEmbed)
.build();
Transaction transaction = new Transaction(params);
TransactionOutput dataOutput = new TransactionOutput(params,
transaction,
Transaction.MIN_NONDUST_OUTPUT,
script.getProgram());
transaction.addOutput(dataOutput);
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(transaction);
// give fee to miners yet. Later it could be spent to other traders via lottery...
sendRequest.fee = Fees.ACCOUNT_REGISTRATION_FEE;
Wallet.SendResult sendResult = null;
sendResult = wallet.sendCoins(sendRequest);
log.info("Registration transaction: " + transaction.toString());
//TODO
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction result)
{
log.info("sendResult onSuccess:" + result.toString());
// Platform.runLater(overlayUi::done);
}
@Override
public void onFailure(Throwable t)
{
log.warn("sendResult onFailure:" + t.toString());
// We died trying to empty the wallet.
// crashAlert(t);
}
});
//TODO
sendResult.tx.getConfidence().addEventListener((tx, reason) -> {
//if (reason == TransactionConfidence.Listener.ChangeReason.SEEN_PEERS)
//updateTitleForBroadcast();
});
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getter // Getter
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public int getRegConfNumBroadcastPeers() /*public int getRegConfNumBroadcastPeers()
{ {
return getAccountRegistrationWallet().getConfNumBroadcastPeers(); return getAccountRegistrationWallet().getConfNumBroadcastPeers();
} }
@ -243,7 +306,7 @@ public class WalletFacade implements WalletEventListener
public int getRegConfDepthInBlocks() public int getRegConfDepthInBlocks()
{ {
return WalletUtil.getConfDepthInBlocks(getAccountRegistrationWallet()); return WalletUtil.getConfDepthInBlocks(getAccountRegistrationWallet());
} } */
public Wallet getWallet() public Wallet getWallet()
{ {
@ -306,13 +369,13 @@ public class WalletFacade implements WalletEventListener
// Private methods // Private methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public AccountRegistrationWallet getAccountRegistrationWallet() /* public AccountRegistrationWallet getAccountRegistrationWallet()
{ {
if (accountRegistrationWallet == null) if (accountRegistrationWallet == null)
accountRegistrationWallet = new AccountRegistrationWallet(params, walletAppKit.chain(), walletAppKit.peerGroup()); accountRegistrationWallet = new AccountRegistrationWallet(params, walletAppKit.chain(), walletAppKit.peerGroup());
return accountRegistrationWallet; return accountRegistrationWallet;
} }*/
private Script getMultiSigScript(String offererPubKey, String takerPubKey, String arbitratorPubKey) private Script getMultiSigScript(String offererPubKey, String takerPubKey, String arbitratorPubKey)
{ {
@ -416,13 +479,14 @@ public class WalletFacade implements WalletEventListener
offererSignatureS, offererSignatureS,
offererPaybackAmount, offererPaybackAmount,
takerPaybackAmount, takerPaybackAmount,
offererAddress); offererAddress, null);
log.info(takerTx.toString()); // tx has 265 Bytes log.info(takerTx.toString()); // tx has 265 Bytes
/* /*
6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba: Unknown confidence level. 6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba: Unknown confidence level.
in [] [30450221008ebd06e53ce1ab7b599098b3117f2073b1d224baae21190ef7839b70a638207602201485ae19965f2d954398f691aa40fecb4d08d625ae96037a4fc5eecb7a4803c301] [30440220521c485045a46fbb61c634ebf456c470f9c2f7307a743e3fce10b50f7a69115d0220249ff5f9796a9fcd12984afcfd3f7d16d2f8c49ddcef245db7c7b02b909af9a601] in [] [30450221008ebd06e53ce1ab7b599098b3117f2073b1d224baae21190ef7839b70a638207602201485ae19965f2d954398f691aa40fecb4d08d625ae96037a4fc5eecb7a4803c301]
[30440220521c485045a46fbb61c634ebf456c470f9c2f7307a743e3fce10b50f7a69115d0220249ff5f9796a9fcd12984afcfd3f7d16d2f8c49ddcef245db7c7b02b909af9a601]
outpoint:4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9:0 hash160:[exception: Script not in the standard scriptPubKey form] outpoint:4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9:0 hash160:[exception: Script not in the standard scriptPubKey form]
out DUP HASH160 [9fc3d8e0371b6eab89a8c3c015839f9e493ccf65] EQUALVERIFY CHECKSIG 0.0289 BTC out DUP HASH160 [9fc3d8e0371b6eab89a8c3c015839f9e493ccf65] EQUALVERIFY CHECKSIG 0.0289 BTC
out DUP HASH160 [e5175c1f71c28218306d4a27c8cec0269dddbbde] EQUALVERIFY CHECKSIG 0.0009 BTC out DUP HASH160 [e5175c1f71c28218306d4a27c8cec0269dddbbde] EQUALVERIFY CHECKSIG 0.0009 BTC
@ -439,19 +503,21 @@ public class WalletFacade implements WalletEventListener
public String getMultiSigPubKeyAsHex() public String getMultiSigPubKeyAsHex()
{ {
return Utils.bytesToHexString(wallet.getKeys().get(0).getPubKey()); return Utils.bytesToHexString(tradingKey.getPubKey());
} }
// deposit 1. offerer // deposit 1. offerer
public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey) throws InsufficientMoneyException public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererInputAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey) throws InsufficientMoneyException
{ {
log.debug("offererCreatesMSTxAndAddPayment");
// use that to use the convenient api for getting the best coin selection and fee calculation // use that to use the convenient api for getting the best coin selection and fee calculation
// TODO should be constructed manually // TODO should be constructed manually
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey); Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
tx.addOutput(offererAmount, multiSigOutputScript); tx.addOutput(offererInputAmount, multiSigOutputScript);
Wallet.SendRequest request = Wallet.SendRequest.forTx(tx); Wallet.SendRequest request = Wallet.SendRequest.forTx(tx);
wallet.completeTx(request); wallet.completeTx(request);
// TODO remove sig or use SigHash.NONE // TODO remove sig or use SigHash.NONE
//tx.getInput(0).setScriptSig(null); //tx.getInput(0).setScriptSig(null);
@ -460,6 +526,8 @@ public class WalletFacade implements WalletEventListener
OUT[0] MS OUT[0] MS
OUT[1] offerer change OUT[1] offerer change
*/ */
log.debug("offererCreatesMSTxAndAddPayment tx = " + tx.toString());
return tx; return tx;
} }
@ -472,6 +540,7 @@ public class WalletFacade implements WalletEventListener
String tx1AsHex String tx1AsHex
) throws InsufficientMoneyException, ExecutionException, InterruptedException, AddressFormatException ) throws InsufficientMoneyException, ExecutionException, InterruptedException, AddressFormatException
{ {
log.debug("takerAddPaymentAndSign");
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey); Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
// use that to use the convenient api for getting the best coin selection and fee calculation // use that to use the convenient api for getting the best coin selection and fee calculation
@ -485,6 +554,8 @@ public class WalletFacade implements WalletEventListener
tx.addOutput(dummyTx.getOutput(1)); tx.addOutput(dummyTx.getOutput(1));
tx.getOutput(0).setValue(msOutputAmount); tx.getOutput(0).setValue(msOutputAmount);
log.debug("tx" + tx.toString());
TransactionInput input = tx.getInput(1); TransactionInput input = tx.getInput(1);
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey(); Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet); ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
@ -498,6 +569,7 @@ public class WalletFacade implements WalletEventListener
else else
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey); throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
log.debug("correctlySpends?");
input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false); input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false);
/* /*
@ -508,6 +580,7 @@ public class WalletFacade implements WalletEventListener
OUT[2] taker change OUT[2] taker change
*/ */
// wallet.commitTx(tx);
return tx; return tx;
} }
@ -555,10 +628,9 @@ public class WalletFacade implements WalletEventListener
log.info("offererSignAndSendTx check correctlySpends input 0"); log.info("offererSignAndSendTx check correctlySpends input 0");
input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false); input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false);
log.info("offererSignAndSendTx check correctlySpends input 1");
input = tx.getInput(1); input = tx.getInput(1);
scriptPubKey = input.getConnectedOutput().getScriptPubKey(); scriptPubKey = input.getConnectedOutput().getScriptPubKey();
log.info("offererSignAndSendTx check correctlySpends input 1");
input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false); input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false);
/* /*
@ -571,15 +643,14 @@ public class WalletFacade implements WalletEventListener
log.info("offererSignAndSendTx broadcastTransaction verify "); log.info("offererSignAndSendTx broadcastTransaction verify ");
tx.verify(); tx.verify();
log.info("offererSignAndSendTx broadcastTransaction pre "); log.info("offererSignAndSendTx broadcastTransaction");
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx); ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx);
log.info("offererSignAndSendTx broadcastTransaction post"); /*FutureCallback<Transaction> localCallback = new FutureCallback<Transaction>()
FutureCallback<Transaction> localCallback = new FutureCallback<Transaction>()
{ {
@Override @Override
public void onSuccess(Transaction transaction) public void onSuccess(Transaction transaction)
{ {
log.info("offererSignAndSendTx onSuccess" + transaction.toString()); log.info("offererSignAndSendTx onSuccess" + transaction.getHashAsString());
} }
@Override @Override
@ -589,19 +660,18 @@ public class WalletFacade implements WalletEventListener
Popups.openErrorPopup("Fee payment failed", "Fee payment failed. " + t.toString()); Popups.openErrorPopup("Fee payment failed", "Fee payment failed. " + t.toString());
} }
}; };
Futures.addCallback(broadcastComplete, localCallback); Futures.addCallback(broadcastComplete, localCallback); */
Futures.addCallback(broadcastComplete, callback); Futures.addCallback(broadcastComplete, callback);
return tx; return tx;
} }
// payout 1. offerer // payout 1. offerer
private Pair<ECKey.ECDSASignature, Transaction> offererCreateAndSignPayoutTx(String depositTxID, public Pair<ECKey.ECDSASignature, Transaction> offererCreateAndSignPayoutTx(String depositTxID,
BigInteger offererPaybackAmount, BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount, BigInteger takerPaybackAmount,
String takerAddress) throws InsufficientMoneyException, AddressFormatException String takerAddress) throws InsufficientMoneyException, AddressFormatException
{ {
ECKey key = wallet.getKeys().get(0);
// offerer has published depositTx so he has it in wallet // offerer has published depositTx so he has it in wallet
Transaction depositTx = wallet.getTransaction(new Sha256Hash(depositTxID)); Transaction depositTx = wallet.getTransaction(new Sha256Hash(depositTxID));
TransactionOutput multiSigOutput = depositTx.getOutput(0); TransactionOutput multiSigOutput = depositTx.getOutput(0);
@ -610,24 +680,24 @@ public class WalletFacade implements WalletEventListener
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
tx.addInput(multiSigOutput); tx.addInput(multiSigOutput);
//TODO fee calculation //TODO fee calculation
tx.addOutput(offererPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), key.toAddress(params)); tx.addOutput(offererPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), tradingKey.toAddress(params));
tx.addOutput(takerPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), new Address(params, takerAddress)); tx.addOutput(takerPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), new Address(params, takerAddress));
Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false); Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature signature = key.sign(sigHash); ECKey.ECDSASignature signature = tradingKey.sign(sigHash);
return new Pair<>(signature, depositTx); return new Pair<>(signature, depositTx);
} }
// payout 2. taker // payout 2. taker
private Transaction takerSignAndSendTx(String depositTxAsHex, public Transaction takerSignAndSendTx(String depositTxAsHex,
String offererSignatureR, String offererSignatureR,
String offererSignatureS, String offererSignatureS,
BigInteger offererPaybackAmount, BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount, BigInteger takerPaybackAmount,
String offererAddress) throws InsufficientMoneyException, AddressFormatException String offererAddress,
FutureCallback<Transaction> callback) throws InsufficientMoneyException, AddressFormatException
{ {
ECKey key = wallet.getKeys().get(0);
Transaction depositTx = new Transaction(params, Utils.parseAsHexOrBase58(depositTxAsHex)); Transaction depositTx = new Transaction(params, Utils.parseAsHexOrBase58(depositTxAsHex));
TransactionOutput multiSigOutput = depositTx.getOutput(0); TransactionOutput multiSigOutput = depositTx.getOutput(0);
@ -636,12 +706,17 @@ public class WalletFacade implements WalletEventListener
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
tx.addInput(multiSigOutput); tx.addInput(multiSigOutput);
//TODO fee calculation //TODO fee calculation
if (offererPaybackAmount.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) <= 0)
log.error("Cannot use such low value");
if (takerPaybackAmount.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) <= 0)
log.error("Cannot use such low value");
tx.addOutput(offererPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), new Address(params, offererAddress)); tx.addOutput(offererPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), new Address(params, offererAddress));
tx.addOutput(takerPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), key.toAddress(params)); tx.addOutput(takerPaybackAmount.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), tradingKey.toAddress(params));
Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false); Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature takerSignature = key.sign(sigHash); ECKey.ECDSASignature takerSignature = tradingKey.sign(sigHash);
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false); TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = new ECKey.ECDSASignature(new BigInteger(offererSignatureR), new BigInteger(offererSignatureS)); ECKey.ECDSASignature offererSignature = new ECKey.ECDSASignature(new BigInteger(offererSignatureR), new BigInteger(offererSignatureS));
@ -650,32 +725,143 @@ public class WalletFacade implements WalletEventListener
Script inputScript = ScriptBuilder.createMultiSigInputScript(ImmutableList.of(offererTxSig, takerTxSig)); Script inputScript = ScriptBuilder.createMultiSigInputScript(ImmutableList.of(offererTxSig, takerTxSig));
tx.getInput(0).setScriptSig(inputScript); tx.getInput(0).setScriptSig(inputScript);
log.info("verify tx");
tx.verify(); tx.verify();
tx.getInput(0).getScriptSig().correctlySpends(tx, 0, multiSigScript, false);
tx.getInput(0).verify(multiSigOutput);
try
{
log.info("verify correctlySpends");
tx.getInput(0).getScriptSig().correctlySpends(tx, 0, multiSigScript, false);
} catch (Exception e)
{
log.error("verify correctlySpends 0:" + e.getMessage());
}
try
{
log.info("verify multiSigOutput");
tx.getInput(0).verify(multiSigOutput);
} catch (Exception e)
{
log.error("verify multiSigOutput 1:" + e.getMessage());
}
log.info("broadcastTransaction:" + tx.toString());
Object t = wallet.getTransactions(true);
log.info("pre broadcastTransaction broadcastTransaction:" + wallet.getTransactions(true).size());
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx); ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx);
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() /* final TransactionBroadcast broadcast = new TransactionBroadcast(walletAppKit.peerGroup(), tx);
broadcast.setMinConnections(1);
Futures.addCallback(broadcast.future(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
// OK, now tell the wallet about the transaction. If the wallet created the transaction then
// it already knows and will ignore this. If it's a transaction we received from
// somebody else via a side channel and are now broadcasting, this will put it into the
// wallet now we know it's valid.
for (Wallet wallet : wallets) {
// Assumption here is there are no dependencies of the created transaction.
//
// We may end up with two threads trying to do this in parallel - the wallet will
// ignore whichever one loses the race.
try {
wallet.receivePending(transaction, null);
} catch (VerificationException e) {
throw new RuntimeException(e); // Cannot fail to verify a tx we created ourselves.
}
}
}
@Override
public void onFailure(Throwable throwable) {
// This can't happen with the current code, but just in case one day that changes ...
// runningBroadcasts.remove(broadcast);
throw new RuntimeException(throwable);
}
}); */
// Keep a reference to the TransactionBroadcast object. This is important because otherwise, the entire tree
// of objects we just created would become garbage if the user doens't hold on to the returned future, and
// eventually be collected. This in turn could result in the transaction not being committed to the wallet
// at all.
// runningBroadcasts.add(broadcast);
// broadcast.broadcast();
FutureCallback<Transaction> localCallback = new FutureCallback<Transaction>()
{ {
@Override @Override
public void onSuccess(Transaction transaction) public void onSuccess(Transaction transaction)
{ {
Object t = wallet.getTransactions(true);
log.info("onSuccess broadcastTransaction:" + wallet.getTransactions(true).size());
log.info("sendResult onSuccess:" + transaction.toString()); log.info("sendResult onSuccess:" + transaction.toString());
log.info("is in wallet?" + wallet.getTransaction(transaction.getHash()).getHashAsString());
/*if (wallet.getTransaction(transaction.getHash()) == null)
wallet.commitTx(transaction); */
log.info("now must be in wallet?" + wallet.getTransaction(transaction.getHash()).getHashAsString());
log.info("##################### now must be in wallet?" + wallet.getTransaction(transaction.getHash()).getHashAsString());
} }
@Override @Override
public void onFailure(Throwable t) public void onFailure(Throwable t)
{ {
log.warn("sendResult onFailure:" + t.toString()); log.warn("sendResult onFailure:" + t.toString());
Popups.openErrorPopup("Fee payment failed", "Fee payment failed. " + t.toString());
} }
}; };
Futures.addCallback(broadcastComplete, localCallback);
Futures.addCallback(broadcastComplete, callback); Futures.addCallback(broadcastComplete, callback);
return tx; return tx;
} }
/*
public ListenableFuture<Transaction> broadcastTransaction(final Transaction tx, final int minConnections) {
final TransactionBroadcast broadcast = new TransactionBroadcast(walletAppKit.peerGroup(), tx);
broadcast.setMinConnections(1);
// Send the TX to the wallet once we have a successful broadcast.
Futures.addCallback(broadcast.future(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
// OK, now tell the wallet about the transaction. If the wallet created the transaction then
// it already knows and will ignore this. If it's a transaction we received from
// somebody else via a side channel and are now broadcasting, this will put it into the
// wallet now we know it's valid.
for (Wallet wallet : wallets) {
// Assumption here is there are no dependencies of the created transaction.
//
// We may end up with two threads trying to do this in parallel - the wallet will
// ignore whichever one loses the race.
try {
wallet.receivePending(transaction, null);
} catch (VerificationException e) {
throw new RuntimeException(e); // Cannot fail to verify a tx we created ourselves.
}
}
}
@Override
public void onFailure(Throwable throwable) {
// This can't happen with the current code, but just in case one day that changes ...
runningBroadcasts.remove(broadcast);
throw new RuntimeException(throwable);
}
});
// Keep a reference to the TransactionBroadcast object. This is important because otherwise, the entire tree
// of objects we just created would become garbage if the user doens't hold on to the returned future, and
// eventually be collected. This in turn could result in the transaction not being committed to the wallet
// at all.
runningBroadcasts.add(broadcast);
broadcast.broadcast();
return broadcast.future();
} */
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Inner classes // Inner classes
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -45,8 +45,8 @@ public class BitSquareModule extends AbstractModule
bind(Trading.class).asEagerSingleton(); bind(Trading.class).asEagerSingleton();
// bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.MAIN_NET); // bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.MAIN_NET);
// bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.REG_TEST_NET); bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.REG_TEST_NET);
bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.TEST_NET); // bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.TEST_NET);
bind(NetworkParameters.class).toProvider(NetworkParametersProvider.class).asEagerSingleton(); bind(NetworkParameters.class).toProvider(NetworkParametersProvider.class).asEagerSingleton();
bind(WalletAppKit.class).toProvider(WalletAppKitProvider.class).asEagerSingleton(); bind(WalletAppKit.class).toProvider(WalletAppKitProvider.class).asEagerSingleton();
} }

View file

@ -305,7 +305,6 @@ public class MainController implements Initializable, NavigationController, Wall
{ {
balanceTextField = new TextField(); balanceTextField = new TextField();
balanceTextField.setEditable(false); balanceTextField.setEditable(false);
balanceTextField.setMouseTransparent(true);
balanceTextField.setPrefWidth(90); balanceTextField.setPrefWidth(90);
balanceTextField.setId("nav-balance-label"); balanceTextField.setId("nav-balance-label");

View file

@ -1,67 +0,0 @@
package io.bitsquare.gui.components;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.util.FormBuilder;
import io.bitsquare.gui.util.Icons;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
public class ConfirmationComponent implements WalletFacade.WalletListener
{
private static final Logger log = LoggerFactory.getLogger(ConfirmationComponent.class);
private ImageView confirmIconImageView;
private TextField confirmationsLabel;
private ProgressIndicator confirmSpinner;
public ConfirmationComponent(WalletFacade walletFacade, GridPane gridPane, int row)
{
confirmationsLabel = FormBuilder.addConfirmationsLabel(gridPane, walletFacade, row);
confirmIconImageView = FormBuilder.addConfirmationsIcon(gridPane, walletFacade, row);
confirmSpinner = FormBuilder.addConfirmationsSpinner(gridPane, walletFacade, row);
}
@Override
public void onConfidenceChanged(int numBroadcastPeers, int depthInBlocks)
{
confirmIconImageView.setImage(getConfirmIconImage(numBroadcastPeers, depthInBlocks));
confirmationsLabel.setText(getConfirmationsText(numBroadcastPeers, depthInBlocks));
if (depthInBlocks == 0 && numBroadcastPeers > 0)
confirmSpinner.setProgress(-1);
else
confirmSpinner.setOpacity(0);
log.info("onConfidenceChanged " + numBroadcastPeers + " / " + depthInBlocks);
}
@Override
public void onCoinsReceived(BigInteger newBalance)
{
log.info("onCoinsReceived " + newBalance);
}
private String getConfirmationsText(int numBroadcastPeers, int depthInBlocks)
{
depthInBlocks = 0;
return depthInBlocks + " confirmation(s) / " + "Seen by " + numBroadcastPeers + " peer(s)";
}
private Image getConfirmIconImage(int numBroadcastPeers, int depthInBlocks)
{
depthInBlocks = 0;
if (depthInBlocks > 0)
return Icons.getIconImage(Icons.getIconIDForConfirmations(depthInBlocks));
else
return Icons.getIconImage(Icons.getIconIDForPeersSeenTx(numBroadcastPeers));
}
}

View file

@ -32,6 +32,7 @@ public class NetworkSyncPane extends HBox
public void doneDownload() public void doneDownload()
{ {
networkSyncInfoLabel.setText("Sync with network: Done"); networkSyncInfoLabel.setText("Sync with network: Done");
networkSyncProgressBar.setProgress(1);
FadeTransition fade = new FadeTransition(Duration.millis(700), this); FadeTransition fade = new FadeTransition(Duration.millis(700), this);
fade.setToValue(0.0); fade.setToValue(0.0);

View file

@ -94,9 +94,10 @@ public class CreateOfferController implements Initializable, ChildController
//TODO //TODO
amountTextField.setText("0,01"); amountTextField.setText("1");
minAmountTextField.setText("0,001"); minAmountTextField.setText("0,1");
priceTextField.setText("500"); priceTextField.setText("500");
collateralTextField.setText("10");
updateVolume(); updateVolume();
amountTextField.textProperty().addListener(new ChangeListener<String>() amountTextField.textProperty().addListener(new ChangeListener<String>()
@ -131,7 +132,7 @@ public class CreateOfferController implements Initializable, ChildController
bankAccountCountyTextField.setText(user.getCurrentBankAccount().getCountryLocale().getDisplayCountry()); bankAccountCountyTextField.setText(user.getCurrentBankAccount().getCountryLocale().getDisplayCountry());
acceptedCountriesTextField.setText(Formatter.countryLocalesToString(settings.getAcceptedCountryLocales())); acceptedCountriesTextField.setText(Formatter.countryLocalesToString(settings.getAcceptedCountryLocales()));
acceptedLanguagesTextField.setText(Formatter.languageLocalesToString(settings.getAcceptedLanguageLocales())); acceptedLanguagesTextField.setText(Formatter.languageLocalesToString(settings.getAcceptedLanguageLocales()));
feeLabel.setText(Utils.bitcoinValueToFriendlyString(Fees.OFFER_CREATION_FEE)); feeLabel.setText(Utils.bitcoinValueToFriendlyString(Fees.OFFER_CREATION_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)));
} }
@ -279,9 +280,9 @@ public class CreateOfferController implements Initializable, ChildController
return priceAsDouble > 0 && return priceAsDouble > 0 &&
amountAsDouble > 0 && amountAsDouble > 0 &&
minAmountAsDouble > 0 && minAmountAsDouble > 0 &&
minAmountAsDouble <= amountAsDouble && minAmountAsDouble <= amountAsDouble/* &&
collateralAsDouble >= settings.getMinCollateral() && collateralAsDouble >= settings.getMinCollateral() &&
collateralAsDouble <= settings.getMaxCollateral(); collateralAsDouble <= settings.getMaxCollateral()*/;
} }
} }

View file

@ -1,5 +1,7 @@
package io.bitsquare.gui.market.trade; package io.bitsquare.gui.market.trade;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.BtcFormatter; import io.bitsquare.btc.BtcFormatter;
@ -14,6 +16,7 @@ import io.bitsquare.gui.util.FormBuilder;
import io.bitsquare.gui.util.Formatter; import io.bitsquare.gui.util.Formatter;
import io.bitsquare.gui.util.Popups; import io.bitsquare.gui.util.Popups;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.TradeMessage;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
@ -37,7 +40,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class TakerTradeController implements Initializable, ChildController, WalletFacade.WalletListener public class TakerTradeController implements Initializable, ChildController
{ {
private static final Logger log = LoggerFactory.getLogger(TakerTradeController.class); private static final Logger log = LoggerFactory.getLogger(TakerTradeController.class);
@ -114,7 +117,6 @@ public class TakerTradeController implements Initializable, ChildController, Wal
@Override @Override
public void initialize(URL url, ResourceBundle rb) public void initialize(URL url, ResourceBundle rb)
{ {
walletFacade.addRegistrationWalletListener(this);
} }
@ -136,27 +138,9 @@ public class TakerTradeController implements Initializable, ChildController, Wal
checkOnlineStatusTimer.stop(); checkOnlineStatusTimer.stop();
checkOnlineStatusTimer = null; checkOnlineStatusTimer = null;
} }
walletFacade.removeRegistrationWalletListener(this);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: WalletFacade.WalletListener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onConfidenceChanged(int numBroadcastPeers, int depthInBlocks)
{
//log.info("onConfidenceChanged " + numBroadcastPeers + " / " + depthInBlocks);
}
@Override
public void onCoinsReceived(BigInteger newBalance)
{
//log.info("onCoinsReceived " + newBalance);
}
//TODO //TODO
public void onPingPeerResult(boolean success) public void onPingPeerResult(boolean success)
{ {
@ -187,7 +171,7 @@ public class TakerTradeController implements Initializable, ChildController, Wal
totalLabel = FormBuilder.addTextField(gridPane, "Total (" + offer.getCurrency() + "):", Formatter.formatVolume(getVolume()), ++row); totalLabel = FormBuilder.addTextField(gridPane, "Total (" + offer.getCurrency() + "):", Formatter.formatVolume(getVolume()), ++row);
collateralTextField = FormBuilder.addTextField(gridPane, "Collateral (BTC):", "", ++row); collateralTextField = FormBuilder.addTextField(gridPane, "Collateral (BTC):", "", ++row);
applyCollateral(); applyCollateral();
FormBuilder.addTextField(gridPane, "Offer fee (BTC):", BtcFormatter.formatSatoshis(Fees.OFFER_TAKER_FEE, false), ++row); FormBuilder.addTextField(gridPane, "Offer fee (BTC):", Utils.bitcoinValueToFriendlyString(Fees.OFFER_TAKER_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)), ++row);
totalToPayLabel = FormBuilder.addTextField(gridPane, "Total to pay (BTC):", getTotalToPay(), ++row); totalToPayLabel = FormBuilder.addTextField(gridPane, "Total to pay (BTC):", getTotalToPay(), ++row);
isOnlineTextField = FormBuilder.addTextField(gridPane, "Online status:", "Checking offerers online status...", ++row); isOnlineTextField = FormBuilder.addTextField(gridPane, "Online status:", "Checking offerers online status...", ++row);
@ -198,9 +182,10 @@ public class TakerTradeController implements Initializable, ChildController, Wal
isOnlineCheckerHolder.getChildren().addAll(isOnlineChecker); isOnlineCheckerHolder.getChildren().addAll(isOnlineChecker);
gridPane.add(isOnlineCheckerHolder, 2, row); gridPane.add(isOnlineCheckerHolder, 2, row);
//TODO
messageFacade.pingPeer(offer.getMessagePubKeyAsHex()); messageFacade.pingPeer(offer.getMessagePubKeyAsHex());
checkOnlineStatusTimer = Utilities.setTimeout(5000, (AnimationTimer animationTimer) -> { checkOnlineStatusTimer = Utilities.setTimeout(1000, (AnimationTimer animationTimer) -> {
setIsOnlineStatus(false); setIsOnlineStatus(true);
return null; return null;
}); });
@ -321,15 +306,26 @@ public class TakerTradeController implements Initializable, ChildController, Wal
} }
@Override @Override
public void onBankTransferInited() public void onBankTransferInited(TradeMessage tradeMessage)
{ {
buildBankTransferInitedScreen(); buildBankTransferInitedScreen(tradeMessage);
}
@Override
public void onTradeCompleted(String hashAsString)
{
showSummary(hashAsString);
} }
}); });
takerPaymentProtocol.takeOffer(); takerPaymentProtocol.takeOffer();
} }
private void updateTx(Trade trade)
{
}
private void buildDepositPublishedScreen(String depositTxID) private void buildDepositPublishedScreen(String depositTxID)
{ {
gridPane.getChildren().clear(); gridPane.getChildren().clear();
@ -338,24 +334,26 @@ public class TakerTradeController implements Initializable, ChildController, Wal
headerLabel = FormBuilder.addHeaderLabel(gridPane, "Deposit transaction published", ++row, 0); headerLabel = FormBuilder.addHeaderLabel(gridPane, "Deposit transaction published", ++row, 0);
infoLabel = FormBuilder.addLabel(gridPane, "Status:", "Deposit transaction published by offerer.\nAs soon as the offerer starts the \nBank transfer, you will get informed.", ++row); infoLabel = FormBuilder.addLabel(gridPane, "Status:", "Deposit transaction published by offerer.\nAs soon as the offerer starts the \nBank transfer, you will get informed.", ++row);
FormBuilder.addTextField(gridPane, "Transaction ID:", depositTxID, ++row, false, true); FormBuilder.addTextField(gridPane, "Transaction ID:", depositTxID, ++row, false, true);
// todo need to load that tx from blockchain, or listen to blockchain
// confidenceDisplay = new ConfidenceDisplay(walletFacade.getWallet(), confirmationLabel, transaction, progressIndicator);
} }
private void buildBankTransferInitedScreen() private void buildBankTransferInitedScreen(TradeMessage tradeMessage)
{ {
processStepBar.next(); processStepBar.next();
headerLabel.setText("Bank transfer inited"); headerLabel.setText("Bank transfer inited");
infoLabel.setText("Check your bank account and continue \nwhen you have received the money."); infoLabel.setText("Check your bank account and continue \nwhen you have received the money.");
log.info("#### grid " + gridPane.getChildren().size());
gridPane.add(nextButton, 1, ++row); gridPane.add(nextButton, 1, ++row);
nextButton.setText("I have received the money at my bank"); nextButton.setText("I have received the money at my bank");
nextButton.setOnAction(e -> releaseBTC()); nextButton.setOnAction(e -> releaseBTC(tradeMessage));
} }
private void releaseBTC() private void releaseBTC(TradeMessage tradeMessage)
{ {
processStepBar.next(); processStepBar.next();
trading.releaseBTC(trade); trading.releaseBTC(trade.getUid(), tradeMessage);
nextButton.setText("Close"); nextButton.setText("Close");
nextButton.setOnAction(e -> close()); nextButton.setOnAction(e -> close());
@ -379,10 +377,14 @@ public class TakerTradeController implements Initializable, ChildController, Wal
gridPane.add(nextButton, 1, ++row); gridPane.add(nextButton, 1, ++row);
} }
private void showSummary(String hashAsString)
{
gridPane.getChildren().clear();
}
private void close() private void close()
{ {
walletFacade.removeRegistrationWalletListener(this);
TabPane tabPane = ((TabPane) (rootContainer.getParent().getParent())); TabPane tabPane = ((TabPane) (rootContainer.getParent().getParent()));
tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
@ -431,11 +433,11 @@ public class TakerTradeController implements Initializable, ChildController, Wal
{ {
if (takerIsSelling()) if (takerIsSelling())
{ {
return BtcFormatter.formatSatoshis(getAmountInSatoshis().add(Fees.OFFER_TAKER_FEE).add(getCollateralInSatoshis()), false); return BtcFormatter.formatSatoshis(getAmountInSatoshis().add(Fees.OFFER_TAKER_FEE).add(Transaction.MIN_NONDUST_OUTPUT).add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE).add(getCollateralInSatoshis()), false);
} }
else else
{ {
return BtcFormatter.formatSatoshis(Fees.OFFER_TAKER_FEE.add(getCollateralInSatoshis()), false) + "\n" + return BtcFormatter.formatSatoshis(Fees.OFFER_TAKER_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE).add(getCollateralInSatoshis()), false) + "\n" +
Formatter.formatVolume(getVolume(), offer.getCurrency()); Formatter.formatVolume(getVolume(), offer.getCurrency());
} }
} }

View file

@ -1,14 +1,19 @@
package io.bitsquare.gui.orders; package io.bitsquare.gui.orders;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction; import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence; import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.core.WalletEventListener;
import com.google.bitcoin.script.Script;
import com.google.inject.Inject; import com.google.inject.Inject;
import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon; import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.bank.BankAccountType; import io.bitsquare.bank.BankAccountType;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.ChildController; import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController; import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.util.ConfidenceDisplay;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.Icons;
import io.bitsquare.gui.util.Localisation; import io.bitsquare.gui.util.Localisation;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
@ -19,6 +24,7 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -34,6 +40,7 @@ import javafx.util.Callback;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.*;
@ -42,10 +49,12 @@ public class OrdersController implements Initializable, ChildController
private static final Logger log = LoggerFactory.getLogger(OrdersController.class); private static final Logger log = LoggerFactory.getLogger(OrdersController.class);
private Trading trading; private Trading trading;
private WalletFacade walletFacade;
private Trade currentTrade; private Trade currentTrade;
private Image buyIcon = Icons.getIconImage(Icons.BUY); private Image buyIcon = Icons.getIconImage(Icons.BUY);
private Image sellIcon = Icons.getIconImage(Icons.SELL); private Image sellIcon = Icons.getIconImage(Icons.SELL);
private ConfidenceDisplay confidenceDisplay;
@FXML @FXML
private TableView openTradesTable; private TableView openTradesTable;
@ -54,9 +63,9 @@ public class OrdersController implements Initializable, ChildController
@FXML @FXML
private ProgressIndicator progressIndicator; private ProgressIndicator progressIndicator;
@FXML @FXML
private Label confidenceLabel, txIDCopyIcon, holderNameCopyIcon, primaryBankAccountIDCopyIcon, secondaryBankAccountIDCopyIcon; private Label confirmationLabel, txIDCopyIcon, holderNameCopyIcon, primaryBankAccountIDCopyIcon, secondaryBankAccountIDCopyIcon;
@FXML @FXML
private TextField txIDTextField, bankAccountTypeTextField, holderNameTextField, primaryBankAccountIDTextField, secondaryBankAccountIDTextField; private TextField txTextField, bankAccountTypeTextField, holderNameTextField, primaryBankAccountIDTextField, secondaryBankAccountIDTextField;
@FXML @FXML
private Button bankTransferInitedButton; private Button bankTransferInitedButton;
@ -66,9 +75,10 @@ public class OrdersController implements Initializable, ChildController
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public OrdersController(Trading trading) public OrdersController(Trading trading, WalletFacade walletFacade)
{ {
this.trading = trading; this.trading = trading;
this.walletFacade = walletFacade;
} }
@ -95,12 +105,44 @@ public class OrdersController implements Initializable, ChildController
openTradesTable.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> { openTradesTable.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue instanceof TradesTableItem) if (newValue instanceof TradesTableItem)
{ {
TradesTableItem tradesTableItem = (TradesTableItem) newValue; showTradeDetails((TradesTableItem) newValue);
fillData(tradesTableItem.getTrade()); }
});
trading.getNewTradeProperty().addListener(new ChangeListener<String>()
{
@Override
public void changed(ObservableValue<? extends String> observableValue, String oldTradeUid, String newTradeUid)
{
Trade newTrade = trading.getTrades().get(newTradeUid);
tradeItems.add(new TradesTableItem(newTrade));
} }
}); });
initCopyIcons(); initCopyIcons();
if (tradeItems.size() > 0)
{
openTradesTable.getSelectionModel().select(0);
}
tradeItems.addListener(new ListChangeListener<TradesTableItem>()
{
@Override
public void onChanged(Change<? extends TradesTableItem> change)
{
if (openTradesTable.getSelectionModel().getSelectedItem() == null && tradeItems.size() > 0)
{
openTradesTable.getSelectionModel().select(0);
}
}
});
}
private void showTradeDetails(TradesTableItem tradesTableItem)
{
fillData(tradesTableItem.getTrade());
} }
@Override @Override
@ -111,62 +153,75 @@ public class OrdersController implements Initializable, ChildController
@Override @Override
public void cleanup() public void cleanup()
{ {
} }
public void bankTransferInited(ActionEvent actionEvent) public void bankTransferInited(ActionEvent actionEvent)
{ {
trading.onBankTransferInited(currentTrade.getUid()); trading.onBankTransferInited(currentTrade.getUid());
bankTransferInitedButton.setDisable(true);
} }
private void updateTx(Trade trade) private void updateTx(Trade trade)
{ {
Transaction transaction = trade.getDepositTransaction(); Transaction transaction = trade.getDepositTransaction();
String txID = "";
if (transaction != null) if (transaction != null)
{ {
txID = transaction.getHashAsString(); confirmationLabel.setVisible(true);
progressIndicator.setVisible(true);
progressIndicator.setProgress(-1);
transaction.getConfidence().addEventListener(new TransactionConfidence.Listener() txTextField.setText(transaction.getHashAsString());
confidenceDisplay = new ConfidenceDisplay(walletFacade.getWallet(), confirmationLabel, transaction, progressIndicator);
int depthInBlocks = transaction.getConfidence().getDepthInBlocks();
bankTransferInitedButton.setDisable(depthInBlocks == 0);
walletFacade.getWallet().addEventListener(new WalletEventListener()
{ {
@Override @Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason) public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{
int depthInBlocks = tx.getConfidence().getDepthInBlocks();
bankTransferInitedButton.setDisable(depthInBlocks == 0);
}
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{
}
@Override
public void onReorganize(Wallet wallet)
{
}
@Override
public void onWalletChanged(Wallet wallet)
{
}
@Override
public void onKeysAdded(Wallet wallet, List<ECKey> keys)
{
}
@Override
public void onScriptsAdded(Wallet wallet, List<Script> scripts)
{ {
updateConfidence(tx);
} }
}); });
} }
else
{
updateConfidence(transaction);
}
txIDTextField.setText(txID);
} }
private void updateConfidence(Transaction tx)
{
TransactionConfidence confidence = tx.getConfidence();
switch (confidence.getConfidenceType())
{
case UNKNOWN:
confidenceLabel.setText("");
progressIndicator.setProgress(0);
break;
case PENDING:
confidenceLabel.setText("Seen by " + confidence.numBroadcastPeers() + " peer(s)");
progressIndicator.setProgress(-1);
break;
case BUILDING:
bankTransferInitedButton.setOpacity(1);
confidenceLabel.setText("Confirmed in " + confidence.getDepthInBlocks() + " block(s)");
progressIndicator.setProgress(Math.min(1, (double) confidence.getDepthInBlocks() / 6.0));
break;
case DEAD:
confidenceLabel.setText("Transaction is invalid.");
break;
}
}
private void fillData(Trade trade) private void fillData(Trade trade)
{ {
@ -189,12 +244,37 @@ public class OrdersController implements Initializable, ChildController
} }
// back details // back details
if (trade.getContract() != null)
{
setBankData(trade);
}
else
{
trade.getContractChangedProperty().addListener(new ChangeListener<Boolean>()
{
@Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean aBoolean2)
{
setBankData(trade);
}
});
}
}
private void setBankData(Trade trade)
{
BankAccount bankAccount = trade.getContract().getTakerBankAccount(); BankAccount bankAccount = trade.getContract().getTakerBankAccount();
//TODO why null?
if (bankAccount != null)
{
bankAccountTypeTextField.setText(bankAccount.getBankAccountType().getType().toString()); bankAccountTypeTextField.setText(bankAccount.getBankAccountType().getType().toString());
holderNameTextField.setText(bankAccount.getAccountHolderName()); holderNameTextField.setText(bankAccount.getAccountHolderName());
primaryBankAccountIDTextField.setText(bankAccount.getAccountPrimaryID()); primaryBankAccountIDTextField.setText(bankAccount.getAccountPrimaryID());
secondaryBankAccountIDTextField.setText(bankAccount.getAccountSecondaryID()); secondaryBankAccountIDTextField.setText(bankAccount.getAccountSecondaryID());
} }
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Table columns // Table columns
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -218,14 +298,14 @@ public class OrdersController implements Initializable, ChildController
} }
@Override @Override
public void updateItem(final TradesTableItem orderBookListItem, boolean empty) public void updateItem(final TradesTableItem tradesTableItem, boolean empty)
{ {
super.updateItem(orderBookListItem, empty); super.updateItem(tradesTableItem, empty);
hBox.getChildren().clear(); hBox.getChildren().clear();
if (orderBookListItem != null) if (tradesTableItem != null)
{ {
Locale countryLocale = orderBookListItem.getTrade().getOffer().getBankAccountCountryLocale(); Locale countryLocale = tradesTableItem.getTrade().getOffer().getBankAccountCountryLocale();
try try
{ {
hBox.getChildren().add(Icons.getIconImageView("/images/countries/" + countryLocale.getCountry().toLowerCase() + ".png")); hBox.getChildren().add(Icons.getIconImageView("/images/countries/" + countryLocale.getCountry().toLowerCase() + ".png"));
@ -253,13 +333,13 @@ public class OrdersController implements Initializable, ChildController
return new TableCell<String, TradesTableItem>() return new TableCell<String, TradesTableItem>()
{ {
@Override @Override
public void updateItem(final TradesTableItem orderBookListItem, boolean empty) public void updateItem(final TradesTableItem tradesTableItem, boolean empty)
{ {
super.updateItem(orderBookListItem, empty); super.updateItem(tradesTableItem, empty);
if (orderBookListItem != null) if (tradesTableItem != null)
{ {
BankAccountType.BankAccountTypeEnum bankAccountTypeEnum = orderBookListItem.getTrade().getOffer().getBankAccountTypeEnum(); BankAccountType.BankAccountTypeEnum bankAccountTypeEnum = tradesTableItem.getTrade().getOffer().getBankAccountTypeEnum();
setText(Localisation.get(bankAccountTypeEnum.toString())); setText(Localisation.get(bankAccountTypeEnum.toString()));
} }
else else
@ -291,15 +371,15 @@ public class OrdersController implements Initializable, ChildController
} }
@Override @Override
public void updateItem(final TradesTableItem orderBookListItem, boolean empty) public void updateItem(final TradesTableItem tradesTableItem, boolean empty)
{ {
super.updateItem(orderBookListItem, empty); super.updateItem(tradesTableItem, empty);
if (orderBookListItem != null) if (tradesTableItem != null)
{ {
String title; String title;
Image icon; Image icon;
Offer offer = orderBookListItem.getTrade().getOffer(); Offer offer = tradesTableItem.getTrade().getOffer();
if (offer.getDirection() == Direction.SELL) if (offer.getDirection() == Direction.SELL)
{ {
@ -339,12 +419,13 @@ public class OrdersController implements Initializable, ChildController
final Button button = new Button("Select"); final Button button = new Button("Select");
@Override @Override
public void updateItem(final TradesTableItem orderBookListItem, boolean empty) public void updateItem(final TradesTableItem tradesTableItem, boolean empty)
{ {
super.updateItem(orderBookListItem, empty); super.updateItem(tradesTableItem, empty);
if (orderBookListItem != null) if (tradesTableItem != null)
{ {
button.setOnAction(event -> showTradeDetails(tradesTableItem));
setGraphic(button); setGraphic(button);
} }
else else
@ -364,7 +445,7 @@ public class OrdersController implements Initializable, ChildController
txIDCopyIcon.setOnMouseClicked(e -> { txIDCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard(); Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent(); ClipboardContent content = new ClipboardContent();
content.putString(txIDTextField.getText()); content.putString(txTextField.getText());
clipboard.setContent(content); clipboard.setContent(content);
}); });
@ -372,7 +453,7 @@ public class OrdersController implements Initializable, ChildController
holderNameCopyIcon.setOnMouseClicked(e -> { holderNameCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard(); Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent(); ClipboardContent content = new ClipboardContent();
content.putString(holderNameCopyIcon.getText()); content.putString(holderNameTextField.getText());
clipboard.setContent(content); clipboard.setContent(content);
}); });
@ -380,7 +461,7 @@ public class OrdersController implements Initializable, ChildController
primaryBankAccountIDCopyIcon.setOnMouseClicked(e -> { primaryBankAccountIDCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard(); Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent(); ClipboardContent content = new ClipboardContent();
content.putString(primaryBankAccountIDCopyIcon.getText()); content.putString(primaryBankAccountIDTextField.getText());
clipboard.setContent(content); clipboard.setContent(content);
}); });
@ -388,7 +469,7 @@ public class OrdersController implements Initializable, ChildController
secondaryBankAccountIDCopyIcon.setOnMouseClicked(e -> { secondaryBankAccountIDCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard(); Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent(); ClipboardContent content = new ClipboardContent();
content.putString(secondaryBankAccountIDCopyIcon.getText()); content.putString(secondaryBankAccountIDTextField.getText());
clipboard.setContent(content); clipboard.setContent(content);
}); });
} }

View file

@ -4,8 +4,9 @@
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?> <?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<VBox prefHeight="540" prefWidth="800" spacing="10" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0" <VBox fx:controller="io.bitsquare.gui.orders.OrdersController" spacing="10" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="io.bitsquare.gui.orders.OrdersController"> AnchorPane.topAnchor="0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1">
<children> <children>
<Label id="headline-label" text="Open trades"> <Label id="headline-label" text="Open trades">
<VBox.margin> <VBox.margin>
@ -13,7 +14,7 @@
</VBox.margin> </VBox.margin>
</Label> </Label>
<TableView fx:id="openTradesTable" id="orderbook-table" prefHeight="150.0"> <TableView id="orderbook-table" fx:id="openTradesTable" prefHeight="150.0">
<columns> <columns>
<TableColumn fx:id="amountColumn" minWidth="120" text="Amount (Min.)"> <TableColumn fx:id="amountColumn" minWidth="120" text="Amount (Min.)">
<cellValueFactory> <cellValueFactory>
@ -56,12 +57,11 @@
<GridPane hgap="5.0" vgap="5.0"> <GridPane hgap="5.0" vgap="5.0">
<children> <children>
<!-- row 0 --> <!-- row 0 -->
<Label id="headline-label" text="Deposit transaction" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="LEFT" <Label id="headline-label" text="Deposit transaction" GridPane.columnSpan="2" GridPane.halignment="LEFT"/>
GridPane.rowIndex="0"/>
<!-- row 1 --> <!-- row 1 -->
<Label text="Transaction ID:" GridPane.columnIndex="0" GridPane.rowIndex="1"/> <Label text="Transaction ID:" GridPane.rowIndex="1"/>
<TextField fx:id="txIDTextField" editable="false" GridPane.columnIndex="1" GridPane.rowIndex="1"/> <TextField fx:id="txTextField" editable="false" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label id="copy-icon" fx:id="txIDCopyIcon" minWidth="10" GridPane.columnIndex="2" GridPane.rowIndex="1"> <Label id="copy-icon" fx:id="txIDCopyIcon" minWidth="10" GridPane.columnIndex="2" GridPane.rowIndex="1">
<padding> <padding>
<Insets bottom="0.0" left="0.0" right="0.0" top="-1.0"/> <Insets bottom="0.0" left="0.0" right="0.0" top="-1.0"/>
@ -70,12 +70,17 @@
<Tooltip text="Copy address to clipboard"/> <Tooltip text="Copy address to clipboard"/>
</tooltip> </tooltip>
</Label> </Label>
<ProgressIndicator fx:id="progressIndicator" prefHeight="20" prefWidth="20" GridPane.columnIndex="3" GridPane.rowIndex="1"/> <ProgressIndicator id="confidence-progress-indicator" fx:id="progressIndicator" visible="false" GridPane.columnIndex="3" GridPane.halignment="LEFT" GridPane.rowIndex="1"
<Label fx:id="confidenceLabel" text="Checking confirmations..." GridPane.columnIndex="4" GridPane.rowIndex="1"/> GridPane.rowSpan="2" GridPane.valignment="TOP">
<GridPane.margin>
<Insets top="2.0"/>
</GridPane.margin>
</ProgressIndicator>
<Label fx:id="confirmationLabel" visible="false" GridPane.columnIndex="4" GridPane.rowIndex="1"/>
<!-- row 2 --> <!-- row 2 -->
<Label id="headline-label" text="Bank details" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="LEFT" <Label id="headline-label" text="Bank details" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="LEFT" GridPane.rowIndex="2"/>
GridPane.rowIndex="2"/>
<!-- row 3 --> <!-- row 3 -->
<Label text="Bank account type:" GridPane.columnIndex="0" GridPane.rowIndex="3"/> <Label text="Bank account type:" GridPane.columnIndex="0" GridPane.rowIndex="3"/>
@ -118,16 +123,15 @@
</Label> </Label>
<!-- row 7 --> <!-- row 7 -->
<Button fx:id="bankTransferInitedButton" defaultButton="true" opacity="0.5" onAction="#bankTransferInited" text="Bank transfer inited" <Button fx:id="bankTransferInitedButton" defaultButton="true" onAction="#bankTransferInited" disable="true" text="Bank transfer inited" GridPane.columnIndex="1" GridPane.rowIndex="7"/>
GridPane.columnIndex="1" GridPane.rowIndex="7"/>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES"/> <ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="400"/> <ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints fillWidth="false" halignment="LEFT" hgrow="NEVER"/> <ColumnConstraints fillWidth="false" hgrow="SOMETIMES" minWidth="20"/>
<ColumnConstraints fillWidth="false" halignment="LEFT" hgrow="SOMETIMES"/> <ColumnConstraints fillWidth="false" hgrow="SOMETIMES" minWidth="20" prefWidth="20"/>
<ColumnConstraints fillWidth="false" halignment="LEFT" hgrow="SOMETIMES"/> <ColumnConstraints fillWidth="false" hgrow="SOMETIMES"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/> <RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>

View file

@ -214,10 +214,10 @@ public class SetupController implements Initializable, ChildController
clipboard.setContent(content); clipboard.setContent(content);
}); });
confidenceDisplay = new ConfidenceDisplay(walletFacade.getAccountRegistrationWallet(), confirmationLabel, balanceTextField, progressIndicator); confidenceDisplay = new ConfidenceDisplay(walletFacade.getWallet(), confirmationLabel, balanceTextField, progressIndicator);
paymentDoneButton.setDisable(walletFacade.getAccountRegistrationBalance().compareTo(BigInteger.ZERO) == 0); paymentDoneButton.setDisable(walletFacade.getAccountRegistrationBalance().compareTo(BigInteger.ZERO) == 0);
log.debug("getAccountRegistrationBalance " + walletFacade.getAccountRegistrationBalance().toString());
walletFacade.getAccountRegistrationWallet().addEventListener(new WalletEventListener() walletFacade.getWallet().addEventListener(new WalletEventListener()
{ {
@Override @Override
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
@ -336,13 +336,13 @@ public class SetupController implements Initializable, ChildController
accountSecondaryID.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState()); accountSecondaryID.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState());
//todo //todo
bankAccountTypesComboBox.getSelectionModel().select(0); /* bankAccountTypesComboBox.getSelectionModel().select(0);
currencyComboBox.getSelectionModel().select(0); currencyComboBox.getSelectionModel().select(0);
countryComboBox.getSelectionModel().select(0); countryComboBox.getSelectionModel().select(0);
accountHolderName.setText("dummy accountHolderName"); accountTitle.setText("Sepa EUR Account");
accountTitle.setText("dummy accountTitle"); accountHolderName.setText("Alice");
accountPrimaryID.setText("dummy accountPrimaryID"); accountPrimaryID.setText("123456");
accountSecondaryID.setText("dummy accountSecondaryID"); accountSecondaryID.setText("7896541"); */
} }
private void setupSettingsScreen() private void setupSettingsScreen()

View file

@ -50,12 +50,14 @@ public class ConfidenceDisplay
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{ {
updateBalance(newBalance); updateBalance(newBalance);
// log.debug("onCoinsReceived " + newBalance);
} }
@Override @Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{ {
updateConfidence(tx); updateConfidence(tx);
// log.debug("onTransactionConfidenceChanged tx " + tx.getHashAsString());
} }
@Override @Override
@ -111,12 +113,14 @@ public class ConfidenceDisplay
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{ {
updateBalance(newBalance); updateBalance(newBalance);
// log.debug("onCoinsReceived " + newBalance);
} }
@Override @Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{ {
updateConfidence(newTransaction); updateConfidence(newTransaction);
// log.debug("onTransactionConfidenceChanged newTransaction " + newTransaction.getHashAsString());
} }
@Override @Override

View file

@ -1,12 +1,12 @@
package io.bitsquare.gui.util; package io.bitsquare.gui.util;
import io.bitsquare.bank.BankAccountType; import io.bitsquare.bank.BankAccountType;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.components.VSpacer; import io.bitsquare.gui.components.VSpacer;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.scene.control.*; import javafx.scene.control.Button;
import javafx.scene.image.Image; import javafx.scene.control.ComboBox;
import javafx.scene.image.ImageView; import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import java.util.Currency; import java.util.Currency;
@ -103,12 +103,12 @@ public class FormBuilder
} */ } */
public static TextField addConfirmationsLabel(GridPane gridPane, WalletFacade walletFacade, int row) /* public static TextField addConfirmationsLabel(GridPane gridPane, WalletFacade walletFacade, int row)
{ {
return FormBuilder.addTextField(gridPane, "Confirmations:", getConfirmationText(walletFacade), row); return FormBuilder.addTextField(gridPane, "Confirmations:", getConfirmationText(walletFacade), row);
} } */
public static ProgressIndicator addConfirmationsSpinner(GridPane gridPane, WalletFacade walletFacade, int row) /* public static ProgressIndicator addConfirmationsSpinner(GridPane gridPane, WalletFacade walletFacade, int row)
{ {
ProgressIndicator progressIndicator = new ProgressIndicator(); ProgressIndicator progressIndicator = new ProgressIndicator();
gridPane.add(progressIndicator, 3, row); gridPane.add(progressIndicator, 3, row);
@ -143,7 +143,7 @@ public class FormBuilder
int numBroadcastPeers = walletFacade.getRegConfNumBroadcastPeers(); int numBroadcastPeers = walletFacade.getRegConfNumBroadcastPeers();
int depthInBlocks = walletFacade.getRegConfDepthInBlocks(); int depthInBlocks = walletFacade.getRegConfDepthInBlocks();
return depthInBlocks + " confirmation(s) / " + "Seen by " + numBroadcastPeers + " peer(s)"; return depthInBlocks + " confirmation(s) / " + "Seen by " + numBroadcastPeers + " peer(s)";
} } */
} }

View file

@ -182,6 +182,7 @@ public class MessageFacade
{ {
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode()); Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
Number160 contentKey = Number160.createHash(offer.getUid()); Number160 contentKey = Number160.createHash(offer.getUid());
log.debug("removeOffer");
FutureDHT removeFuture = myPeer.remove(locationKey).setReturnResults().setContentKey(contentKey).start(); FutureDHT removeFuture = myPeer.remove(locationKey).setReturnResults().setContentKey(contentKey).start();
removeFuture.addListener(new BaseFutureAdapter<BaseFuture>() removeFuture.addListener(new BaseFutureAdapter<BaseFuture>()
{ {
@ -196,6 +197,7 @@ public class MessageFacade
private void onOfferRemoved(Data data, boolean success, Number160 locationKey) private void onOfferRemoved(Data data, boolean success, Number160 locationKey)
{ {
log.debug("onOfferRemoved");
setDirty(locationKey); setDirty(locationKey);
for (OrderBookListener orderBookListener : orderBookListeners) for (OrderBookListener orderBookListener : orderBookListeners)
@ -456,7 +458,11 @@ public class MessageFacade
break; break;
case BANK_TX_INITED: case BANK_TX_INITED:
for (TakerPaymentProtocol takeOfferTradeListener : takerPaymentProtocols) for (TakerPaymentProtocol takeOfferTradeListener : takerPaymentProtocols)
takeOfferTradeListener.onBankTransferInited(); takeOfferTradeListener.onBankTransferInited(tradeMessage);
break;
case PAYOUT_TX_PUBLISHED:
for (OffererPaymentProtocol offererPaymentProtocol : offererPaymentProtocols)
offererPaymentProtocol.onPayoutTxPublished(tradeMessage);
break; break;
default: default:
@ -638,7 +644,7 @@ public class MessageFacade
private void setupStorage() throws IOException private void setupStorage() throws IOException
{ {
//TODO BitSquare.ID just temp... //TODO BitSquare.ID just temp...
String dirPath = Utilities.getRootDir() + "tomP2P_" + BitSquare.ID; String dirPath = Utilities.getRootDir() + BitSquare.ID + "_tomP2P";
File dirFile = new File(dirPath); File dirFile = new File(dirPath);
boolean success = true; boolean success = true;
if (!dirFile.exists()) if (!dirFile.exists())

View file

@ -18,8 +18,14 @@ public class TradeMessage implements Serializable
private String txConnOutAsHex; private String txConnOutAsHex;
private String contractAsJson; private String contractAsJson;
private String takerContractSignature; private String takerContractSignature;
private String takerPayoutAddress;
private TradeMessageType type; private TradeMessageType type;
private String depositTxID; private String depositTxID;
private String offererSignatureR;
private String offererSignatureS;
private BigInteger offererPaybackAmount;
private BigInteger takerPaybackAmount;
private String offererPayoutAddress;
private BigInteger tradeAmount; private BigInteger tradeAmount;
private String takeOfferFeeTxID; private String takeOfferFeeTxID;
private String takerMultiSigPubKey; private String takerMultiSigPubKey;
@ -28,6 +34,7 @@ public class TradeMessage implements Serializable
private String accountID; private String accountID;
private String offererPubKey; private String offererPubKey;
private String preparedOffererDepositTxAsHex; private String preparedOffererDepositTxAsHex;
private String payoutTxID;
public TradeMessage(TradeMessageType type, String offerUID) public TradeMessage(TradeMessageType type, String offerUID)
{ {
@ -37,6 +44,7 @@ public class TradeMessage implements Serializable
uid = UUID.randomUUID().toString(); uid = UUID.randomUUID().toString();
} }
public TradeMessage(TradeMessageType type, String offerUID, BigInteger tradeAmount, String takeOfferFeeTxID, String takerMultiSigPubKey) public TradeMessage(TradeMessageType type, String offerUID, BigInteger tradeAmount, String takeOfferFeeTxID, String takerMultiSigPubKey)
{ {
this.offerUID = offerUID; this.offerUID = offerUID;
@ -68,7 +76,8 @@ public class TradeMessage implements Serializable
String txScriptSigAsHex, String txScriptSigAsHex,
String txConnOutAsHex, String txConnOutAsHex,
String contractAsJson, String contractAsJson,
String takerContractSignature) String takerContractSignature,
String takerPayoutAddress)
{ {
this.offerUID = offerUID; this.offerUID = offerUID;
this.type = type; this.type = type;
@ -80,6 +89,7 @@ public class TradeMessage implements Serializable
this.txConnOutAsHex = txConnOutAsHex; this.txConnOutAsHex = txConnOutAsHex;
this.contractAsJson = contractAsJson; this.contractAsJson = contractAsJson;
this.takerContractSignature = takerContractSignature; this.takerContractSignature = takerContractSignature;
this.takerPayoutAddress = takerPayoutAddress;
uid = UUID.randomUUID().toString(); uid = UUID.randomUUID().toString();
} }
@ -93,6 +103,28 @@ public class TradeMessage implements Serializable
uid = UUID.randomUUID().toString(); uid = UUID.randomUUID().toString();
} }
// 3.10
public TradeMessage(TradeMessageType type, String offerUID,
String depositTxID,
String offererSignatureR,
String offererSignatureS,
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererPayoutAddress)
{
this.offerUID = offerUID;
this.type = type;
this.depositTxID = depositTxID;
this.offererSignatureR = offererSignatureR;
this.offererSignatureS = offererSignatureS;
this.offererPaybackAmount = offererPaybackAmount;
this.takerPaybackAmount = takerPaybackAmount;
this.offererPayoutAddress = offererPayoutAddress;
uid = UUID.randomUUID().toString();
}
public String getUid() public String getUid()
{ {
@ -178,4 +210,46 @@ public class TradeMessage implements Serializable
{ {
return offererPubKey; return offererPubKey;
} }
public String getTakerPayoutAddress()
{
return takerPayoutAddress;
}
public String getOffererPayoutAddress()
{
return offererPayoutAddress;
}
public String getOffererSignatureR()
{
return offererSignatureR;
}
public String getOffererSignatureS()
{
return offererSignatureS;
}
public BigInteger getOffererPaybackAmount()
{
return offererPaybackAmount;
}
public BigInteger getTakerPaybackAmount()
{
return takerPaybackAmount;
}
public String getPayoutTxID()
{
return payoutTxID;
}
public void setPayoutTxID(String payoutTxID)
{
this.payoutTxID = payoutTxID;
}
} }

View file

@ -9,5 +9,7 @@ public enum TradeMessageType
REQUEST_TAKER_DEPOSIT_PAYMENT, REQUEST_TAKER_DEPOSIT_PAYMENT,
REQUEST_OFFERER_DEPOSIT_PUBLICATION, REQUEST_OFFERER_DEPOSIT_PUBLICATION,
DEPOSIT_TX_PUBLISHED, DEPOSIT_TX_PUBLISHED,
BANK_TX_INITED BANK_TX_INITED,
PAYOUT_TX_PUBLISHED
} }

View file

@ -17,7 +17,7 @@ public class Storage
private static final Logger log = LoggerFactory.getLogger(Storage.class); private static final Logger log = LoggerFactory.getLogger(Storage.class);
//TODO save in users preferences location //TODO save in users preferences location
private final String preferencesFileName = "pref_" + BitSquare.ID + ".ser"; private final String preferencesFileName = BitSquare.ID + "_pref" + ".ser";
private final String storageFile; private final String storageFile;
private Map<String, Object> dict; private Map<String, Object> dict;

View file

@ -11,6 +11,7 @@ public class Trade implements Serializable
private static final long serialVersionUID = -8275323072940974077L; private static final long serialVersionUID = -8275323072940974077L;
transient private final SimpleBooleanProperty depositTxChangedProperty = new SimpleBooleanProperty(); transient private final SimpleBooleanProperty depositTxChangedProperty = new SimpleBooleanProperty();
transient private final SimpleBooleanProperty contractChangedProperty = new SimpleBooleanProperty();
private Offer offer; private Offer offer;
private String takeOfferFeeTxID; private String takeOfferFeeTxID;
@ -43,6 +44,7 @@ public class Trade implements Serializable
public void setContract(Contract contract) public void setContract(Contract contract)
{ {
this.contract = contract; this.contract = contract;
contractChangedProperty.set(!contractChangedProperty.get());
} }
public void setContractAsJson(String contractAsJson) public void setContractAsJson(String contractAsJson)
@ -110,6 +112,12 @@ public class Trade implements Serializable
{ {
return depositTxChangedProperty; return depositTxChangedProperty;
} }
public SimpleBooleanProperty getContractChangedProperty()
{
return contractChangedProperty;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// toString // toString
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -18,6 +18,8 @@ import io.bitsquare.trade.offerer.OffererPaymentProtocolListener;
import io.bitsquare.trade.taker.TakerPaymentProtocol; import io.bitsquare.trade.taker.TakerPaymentProtocol;
import io.bitsquare.trade.taker.TakerPaymentProtocolListener; import io.bitsquare.trade.taker.TakerPaymentProtocolListener;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -36,8 +38,6 @@ public class Trading
private Map<String, Offer> myOffers = new HashMap<>(); private Map<String, Offer> myOffers = new HashMap<>();
private Map<String, Trade> trades = new HashMap<>(); private Map<String, Trade> trades = new HashMap<>();
private final Map<String, TakerPaymentProtocol> takerPaymentProtocols = new HashMap<>(); private final Map<String, TakerPaymentProtocol> takerPaymentProtocols = new HashMap<>();
private final Map<String, OffererPaymentProtocol> offererPaymentProtocols = new HashMap<>(); private final Map<String, OffererPaymentProtocol> offererPaymentProtocols = new HashMap<>();
private final String storageKey; private final String storageKey;
private User user; private User user;
@ -47,6 +47,7 @@ public class Trading
private WalletFacade walletFacade; private WalletFacade walletFacade;
private CryptoFacade cryptoFacade; private CryptoFacade cryptoFacade;
private Settings settings; private Settings settings;
private final StringProperty newTradeProperty = new SimpleStringProperty();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -101,8 +102,9 @@ public class Trading
throw new IllegalStateException("offers contains already a offer with the ID " + offer.getUid()); throw new IllegalStateException("offers contains already a offer with the ID " + offer.getUid());
myOffers.put(offer.getUid(), offer); myOffers.put(offer.getUid(), offer);
storage.write(storageKey + ".offers", myOffers); //TODO for testing
walletFacade.payFee(Fees.OFFER_CREATION_FEE, callback); //storage.write(storageKey + ".offers", myOffers);
walletFacade.payOfferFee(Fees.OFFER_CREATION_FEE, callback);
} }
public void removeOffer(Offer offer) throws IOException public void removeOffer(Offer offer) throws IOException
@ -113,12 +115,16 @@ public class Trading
public Trade createTrade(Offer offer) public Trade createTrade(Offer offer)
{ {
/* if (trades.containsKey(offer.getUid())) if (trades.containsKey(offer.getUid()))
throw new IllegalStateException("trades contains already a trade with the ID " + offer.getUid()); */ throw new IllegalStateException("trades contains already a trade with the ID " + offer.getUid());
Trade trade = new Trade(offer); Trade trade = new Trade(offer);
trades.put(offer.getUid(), trade); trades.put(offer.getUid(), trade);
storage.write(storageKey + ".trades", trades); //TODO for testing
//storage.write(storageKey + ".trades", trades);
this.newTradeProperty.set(trade.getUid());
return trade; return trade;
} }
@ -128,6 +134,11 @@ public class Trading
storage.write(storageKey + ".trades", trades); storage.write(storageKey + ".trades", trades);
} }
public final StringProperty getNewTradeProperty()
{
return this.newTradeProperty;
}
public TakerPaymentProtocol addTakerPaymentProtocol(Trade trade, TakerPaymentProtocolListener listener) public TakerPaymentProtocol addTakerPaymentProtocol(Trade trade, TakerPaymentProtocolListener listener)
{ {
TakerPaymentProtocol takerPaymentProtocol = new TakerPaymentProtocol(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user); TakerPaymentProtocol takerPaymentProtocol = new TakerPaymentProtocol(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
@ -172,6 +183,12 @@ public class Trading
log.debug("trading onDepositTxConfirmedUpdate"); log.debug("trading onDepositTxConfirmedUpdate");
} }
@Override
public void onPayoutTxPublished(String payoutTxID)
{
log.debug("trading onPayoutTxPublished");
}
@Override @Override
public void onDepositTxConfirmedInBlockchain() public void onDepositTxConfirmedInBlockchain()
{ {
@ -198,14 +215,9 @@ public class Trading
// 6 // 6
public void releaseBTC(Trade trade) public void releaseBTC(String tradeUID, TradeMessage tradeMessage)
{ {
log.info("Sign payment tx"); takerPaymentProtocols.get(tradeUID).releaseBTC(tradeMessage);
log.info("Broadcast payment tx");
log.info("Send message to peer that payment Tx has been broadcasted.");
// messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -1,9 +1,6 @@
package io.bitsquare.trade.offerer; package io.bitsquare.trade.offerer;
import com.google.bitcoin.core.InsufficientMoneyException; import com.google.bitcoin.core.*;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence;
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.BlockChainFacade;
@ -18,6 +15,7 @@ import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import javafx.util.Pair;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -44,9 +42,11 @@ public class OffererPaymentProtocol
private User user; private User user;
private PeerAddress peerAddress; private PeerAddress peerAddress;
private boolean isTakeOfferRequested; private boolean isTakeOfferRequested;
private int numberOfSteps = 20;//TODO private int numberOfSteps = 15;//TODO
private int currentStep = 0; private int currentStep = 0;
private String preparedOffererDepositTxAsHex; private String preparedOffererDepositTxAsHex;
private Transaction depositTransaction;
private String takerPayoutAddress;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
@ -118,9 +118,11 @@ public class OffererPaymentProtocol
isTakeOfferRequested = true; isTakeOfferRequested = true;
try try
{ {
log.debug("1.3 messageFacade.removeOffer");
messageFacade.removeOffer(offer); messageFacade.removeOffer(offer);
} catch (IOException e) } catch (IOException e)
{ {
log.error("1.3 messageFacade.removeOffer failed " + e.getMessage());
offererPaymentProtocolListener.onFailure("removeOffer failed " + e.getMessage()); offererPaymentProtocolListener.onFailure("removeOffer failed " + e.getMessage());
} }
@ -212,7 +214,7 @@ public class OffererPaymentProtocol
log.debug("2.5 createDepositTx"); log.debug("2.5 createDepositTx");
BigInteger collateralAmount = trade.getTradeAmount().multiply(BigInteger.valueOf(offer.getCollateral())).divide(BigInteger.valueOf(100)); BigInteger offererInputAmount = trade.getTradeAmount().multiply(BigInteger.valueOf(offer.getCollateral())).divide(BigInteger.valueOf(100));
String offererPubKey = walletFacade.getMultiSigPubKeyAsHex(); String offererPubKey = walletFacade.getMultiSigPubKeyAsHex();
String takerPubKey = requestTradeMessage.getTakerMultiSigPubKey(); String takerPubKey = requestTradeMessage.getTakerMultiSigPubKey();
String arbitratorPubKey = offer.getArbitrator().getPubKey(); String arbitratorPubKey = offer.getArbitrator().getPubKey();
@ -223,13 +225,13 @@ public class OffererPaymentProtocol
checkNotNull(arbitratorPubKey); checkNotNull(arbitratorPubKey);
log.debug("2.5 offererCreatesMSTxAndAddPayment"); log.debug("2.5 offererCreatesMSTxAndAddPayment");
log.debug("collateralAmount " + collateralAmount); log.debug("offererInputAmount " + Utils.bitcoinValueToFriendlyString(offererInputAmount));
log.debug("offerer pubkey " + offererPubKey); log.debug("offerer pubkey " + offererPubKey);
log.debug("taker pubkey " + takerPubKey); log.debug("taker pubkey " + takerPubKey);
log.debug("arbitrator pubkey " + arbitratorPubKey); log.debug("arbitrator pubkey " + arbitratorPubKey);
try try
{ {
Transaction tx = walletFacade.offererCreatesMSTxAndAddPayment(collateralAmount, offererPubKey, takerPubKey, arbitratorPubKey); Transaction tx = walletFacade.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerPubKey, arbitratorPubKey);
preparedOffererDepositTxAsHex = Utils.bytesToHexString(tx.bitcoinSerialize()); preparedOffererDepositTxAsHex = Utils.bytesToHexString(tx.bitcoinSerialize());
log.debug("2.5 deposit tx created: " + tx); log.debug("2.5 deposit tx created: " + tx);
log.debug("2.5 deposit txAsHex: " + preparedOffererDepositTxAsHex); log.debug("2.5 deposit txAsHex: " + preparedOffererDepositTxAsHex);
@ -237,6 +239,8 @@ public class OffererPaymentProtocol
} catch (InsufficientMoneyException e) } catch (InsufficientMoneyException e)
{ {
log.warn("2.5 InsufficientMoneyException " + e.getMessage()); log.warn("2.5 InsufficientMoneyException " + e.getMessage());
//110010000
// 20240000
} }
} }
@ -298,6 +302,7 @@ public class OffererPaymentProtocol
public void onDepositTxReadyForPublication(TradeMessage requestTradeMessage) public void onDepositTxReadyForPublication(TradeMessage requestTradeMessage)
{ {
log.debug("3.1 onDepositTxReadyForPublication"); log.debug("3.1 onDepositTxReadyForPublication");
takerPayoutAddress = requestTradeMessage.getTakerPayoutAddress();
verifyTaker(requestTradeMessage); verifyTaker(requestTradeMessage);
} }
@ -350,24 +355,29 @@ public class OffererPaymentProtocol
log.debug("3.3 contractAsJson: " + contractAsJson); log.debug("3.3 contractAsJson: " + contractAsJson);
log.debug("3.3 requestTradingMessage.getContractAsJson(): " + requestTradeMessage.getContractAsJson()); log.debug("3.3 requestTradingMessage.getContractAsJson(): " + requestTradeMessage.getContractAsJson());
// TODO generic json creates too complex object, at least the PublicKeys need to be removed if (contractAsJson.equals(requestTradeMessage.getContractAsJson()))
boolean isEqual = contractAsJson.equals(requestTradeMessage.getContractAsJson()); {
log.debug("3.3 does json match?: " + isEqual); log.debug("3.3 The 2 contracts as json does match");
String signature = cryptoFacade.signContract(walletFacade.getRegistrationKey(), contractAsJson);
/* if (contractAsJson.equals(requestTradingMessage.getContractAsJson()))
{ */
String signature = cryptoFacade.signContract(walletFacade.getAccountRegistrationKey(), contractAsJson);
trade.setContract(contract); trade.setContract(contract);
trade.setContractAsJson(contractAsJson); trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature); trade.setContractTakerSignature(signature);
log.debug("3.3 signature: " + signature); log.debug("3.3 signature: " + signature);
signAndPublishDepositTx(requestTradeMessage); signAndPublishDepositTx(requestTradeMessage);
/* } }
else else
{ {
log.error("3.3 verifyContract failed"); log.error("3.3 verifyContract failed");
} */ //TODO ignore that for now... fee inconsistency...
String signature = cryptoFacade.signContract(walletFacade.getRegistrationKey(), contractAsJson);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
log.debug("3.3 signature: " + signature);
signAndPublishDepositTx(requestTradeMessage);
}
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -388,6 +398,12 @@ public class OffererPaymentProtocol
public void onSuccess(Transaction transaction) public void onSuccess(Transaction transaction)
{ {
log.info("3.4 signAndPublishDepositTx offererSignAndSendTx onSuccess:" + transaction.toString()); log.info("3.4 signAndPublishDepositTx offererSignAndSendTx onSuccess:" + transaction.toString());
String txID = transaction.getHashAsString();
trade.setDepositTransaction(transaction);
log.debug("3.4 deposit tx published: " + transaction);
log.debug("3.4 deposit txID: " + txID);
sendDepositTxIdToTaker(transaction);
} }
@Override @Override
@ -399,13 +415,7 @@ public class OffererPaymentProtocol
try try
{ {
log.debug("3.4 offererSignAndSendTx"); log.debug("3.4 offererSignAndSendTx");
Transaction transaction = walletFacade.offererSignAndSendTx(preparedOffererDepositTxAsHex, signedTakerDepositTxAsHex, txConnOutAsHex, txScriptSigAsHex, callback); depositTransaction = walletFacade.offererSignAndSendTx(preparedOffererDepositTxAsHex, signedTakerDepositTxAsHex, txConnOutAsHex, txScriptSigAsHex, callback);
String txID = transaction.getHashAsString();
trade.setDepositTransaction(transaction);
log.debug("3.4 deposit tx published: " + transaction);
log.debug("3.4 deposit txID: " + txID);
sendDepositTxIdToTaker(transaction);
} catch (Exception e) } catch (Exception e)
{ {
log.error("3.4 error at walletFacade.offererSignAndSendTx: " + e.getMessage()); log.error("3.4 error at walletFacade.offererSignAndSendTx: " + e.getMessage());
@ -469,20 +479,16 @@ public class OffererPaymentProtocol
@Override @Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason) public void onConfidenceChanged(Transaction tx, ChangeReason reason)
{ {
log.info("onConfidenceChanged reason = " + reason);
log.info("onConfidenceChanged confidence = " + tx.getConfidence().toString());
if (reason == ChangeReason.SEEN_PEERS) if (reason == ChangeReason.SEEN_PEERS)
{ {
updateConfirmation(tx.getConfidence()); updateConfirmation(tx.getConfidence());
log.debug("### confidence.numBroadcastPeers() " + tx.getConfidence().numBroadcastPeers());
//todo just for testing now, dont like to wait so long... //todo just for testing now, dont like to wait so long...
if (tx.getConfidence().numBroadcastPeers() > 3) /* if (tx.getConfidence().numBroadcastPeers() > 3)
{ {
onDepositTxConfirmedInBlockchain(); onDepositTxConfirmedInBlockchain();
transaction.getConfidence().removeEventListener(this); transaction.getConfidence().removeEventListener(this);
} } */
} }
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
@ -534,8 +540,6 @@ public class OffererPaymentProtocol
public void onResult() public void onResult()
{ {
log.debug("3.10 bankTransferInited BANK_TX_INITED onResult"); log.debug("3.10 bankTransferInited BANK_TX_INITED onResult");
log.debug("########## LAST STEP OFFERER FOR FIRST PART");
offererPaymentProtocolListener.onProgress(getProgress()); offererPaymentProtocolListener.onProgress(getProgress());
} }
@ -546,9 +550,52 @@ public class OffererPaymentProtocol
offererPaymentProtocolListener.onFailure("bankTransferInited BANK_TX_INITED"); offererPaymentProtocolListener.onFailure("bankTransferInited BANK_TX_INITED");
} }
}; };
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.BANK_TX_INITED, trade.getUid());
try
{
BigInteger collateral = trade.getTradeAmount().multiply(BigInteger.valueOf(offer.getCollateral())).divide(BigInteger.valueOf(100));
BigInteger offererPaybackAmount = trade.getTradeAmount().add(collateral);
BigInteger takerPaybackAmount = collateral;
log.debug("offererPaybackAmount " + offererPaybackAmount.toString());
log.debug("takerPaybackAmount " + takerPaybackAmount.toString());
log.debug("depositTransaction.getHashAsString() " + depositTransaction.getHashAsString());
log.debug("takerPayoutAddress " + takerPayoutAddress);
log.debug("walletFacade.offererCreateAndSignPayoutTx");
Pair<ECKey.ECDSASignature, Transaction> result = walletFacade.offererCreateAndSignPayoutTx(depositTransaction.getHashAsString(), offererPaybackAmount, takerPaybackAmount, takerPayoutAddress);
ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString();
String offererSignatureS = offererSignature.s.toString();
Transaction depositTx = result.getValue();
String depositTxID = Utils.bytesToHexString(depositTx.bitcoinSerialize());
String offererPayoutAddress = walletFacade.getAddressAsString();
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.BANK_TX_INITED, trade.getUid(),
depositTxID,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
log.debug("depositTxID " + depositTxID);
log.debug("offererSignatureR " + offererSignatureR);
log.debug("offererSignatureS " + offererSignatureS);
log.debug("offererPaybackAmount " + offererPaybackAmount.toString());
log.debug("takerPaybackAmount " + takerPaybackAmount.toString());
log.debug("offererPayoutAddress " + offererPayoutAddress);
log.debug("3.10 sendTradingMessage BANK_TX_INITED"); log.debug("3.10 sendTradingMessage BANK_TX_INITED");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener); messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
} catch (InsufficientMoneyException e)
{
log.error("3.10 offererCreateAndSignPayoutTx onFailed InsufficientMoneyException " + e.getMessage());
} catch (AddressFormatException e)
{
log.error("3.10 offererCreateAndSignPayoutTx onFailed AddressFormatException " + e.getMessage());
}
} }
@ -557,9 +604,29 @@ public class OffererPaymentProtocol
//************************************************************************************************ //************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.14 We received the payout tx. Trade is completed
///////////////////////////////////////////////////////////////////////////////////////////
public void onPayoutTxPublished(TradeMessage tradeMessage)
{
log.debug("3.14 onPayoutTxPublished");
log.debug("3.14 TRADE COMPLETE!!!!!!!!!!!");
walletFacade.updateWallet();
offererPaymentProtocolListener.onPayoutTxPublished(tradeMessage.getPayoutTxID());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Util
///////////////////////////////////////////////////////////////////////////////////////////
private double getProgress() private double getProgress()
{ {
currentStep++; currentStep++;
return (double) currentStep / (double) numberOfSteps; return (double) currentStep / (double) numberOfSteps;
} }
} }

View file

@ -13,4 +13,6 @@ public interface OffererPaymentProtocolListener
void onDepositTxConfirmedInBlockchain(); void onDepositTxConfirmedInBlockchain();
void onDepositTxConfirmedUpdate(TransactionConfidence confidence); void onDepositTxConfirmedUpdate(TransactionConfidence confidence);
void onPayoutTxPublished(String payoutTxID);
} }

View file

@ -3,6 +3,7 @@ package io.bitsquare.trade.taker;
import com.google.bitcoin.core.AddressFormatException; import com.google.bitcoin.core.AddressFormatException;
import com.google.bitcoin.core.InsufficientMoneyException; import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction; import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.BlockChainFacade;
@ -43,8 +44,7 @@ public class TakerPaymentProtocol
private CryptoFacade cryptoFacade; private CryptoFacade cryptoFacade;
private User user; private User user;
private PeerAddress peerAddress; private PeerAddress peerAddress;
private boolean isTakeOfferRequested; private int numberOfSteps = 15;//TODO
private int numberOfSteps = 6;//TODO
private int currentStep = 0; private int currentStep = 0;
@ -217,7 +217,7 @@ public class TakerPaymentProtocol
{ {
// Pay the offer fee // Pay the offer fee
takerPaymentProtocolListener.onProgress(getProgress()); takerPaymentProtocolListener.onProgress(getProgress());
walletFacade.payFee(Fees.OFFER_TAKER_FEE, callback); walletFacade.payOfferFee(Fees.OFFER_TAKER_FEE, callback);
} catch (InsufficientMoneyException e) } catch (InsufficientMoneyException e)
{ {
takerPaymentProtocolListener.onProgress(getProgress()); takerPaymentProtocolListener.onProgress(getProgress());
@ -341,7 +341,7 @@ public class TakerPaymentProtocol
log.debug("2.9 contract created: " + contract.toString()); log.debug("2.9 contract created: " + contract.toString());
String contractAsJson = Utilities.objectToJson(contract); String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(walletFacade.getAccountRegistrationKey(), contractAsJson); String signature = cryptoFacade.signContract(walletFacade.getRegistrationKey(), contractAsJson);
//log.debug("2.9 contractAsJson: " + contractAsJson); //log.debug("2.9 contractAsJson: " + contractAsJson);
log.debug("2.9 contract signature: " + signature); log.debug("2.9 contract signature: " + signature);
@ -363,14 +363,17 @@ public class TakerPaymentProtocol
log.debug("2.10 payDeposit"); log.debug("2.10 payDeposit");
BigInteger collateralAmount = trade.getTradeAmount().multiply(BigInteger.valueOf(offer.getCollateral())).divide(BigInteger.valueOf(100)); BigInteger collateralAmount = trade.getTradeAmount().multiply(BigInteger.valueOf(offer.getCollateral())).divide(BigInteger.valueOf(100));
BigInteger takerAmount = trade.getTradeAmount().add(collateralAmount); BigInteger takerInputAmount = trade.getTradeAmount().add(collateralAmount);
BigInteger msOutputAmount = trade.getTradeAmount().add(collateralAmount).add(collateralAmount);
// trade + 2 x coll + 1 x btc network fee
BigInteger msOutputAmount = trade.getTradeAmount().add(collateralAmount).add(collateralAmount).add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
String offererPubKey = requestTradeMessage.getOffererPubKey(); String offererPubKey = requestTradeMessage.getOffererPubKey();
String takerPubKey = walletFacade.getMultiSigPubKeyAsHex(); String takerPubKey = walletFacade.getMultiSigPubKeyAsHex();
String arbitratorPubKey = offer.getArbitrator().getPubKey(); String arbitratorPubKey = offer.getArbitrator().getPubKey();
String preparedOffererDepositTxAsHex = requestTradeMessage.getPreparedOffererDepositTxAsHex(); String preparedOffererDepositTxAsHex = requestTradeMessage.getPreparedOffererDepositTxAsHex();
checkNotNull(takerAmount); checkNotNull(takerInputAmount);
checkNotNull(msOutputAmount); checkNotNull(msOutputAmount);
checkNotNull(offererPubKey); checkNotNull(offererPubKey);
checkNotNull(takerPubKey); checkNotNull(takerPubKey);
@ -378,15 +381,15 @@ public class TakerPaymentProtocol
checkNotNull(preparedOffererDepositTxAsHex); checkNotNull(preparedOffererDepositTxAsHex);
log.debug("2.10 offererCreatesMSTxAndAddPayment"); log.debug("2.10 offererCreatesMSTxAndAddPayment");
log.debug("takerAmount " + takerAmount); log.debug("takerAmount " + Utils.bitcoinValueToFriendlyString(takerInputAmount));
log.debug("msOutputAmount " + msOutputAmount); log.debug("msOutputAmount " + Utils.bitcoinValueToFriendlyString(msOutputAmount));
log.debug("offerer pubkey " + offererPubKey); log.debug("offerer pubkey " + offererPubKey);
log.debug("taker pubkey " + takerPubKey); log.debug("taker pubkey " + takerPubKey);
log.debug("arbitrator pubkey " + arbitratorPubKey); log.debug("arbitrator pubkey " + arbitratorPubKey);
log.debug("preparedOffererDepositTxAsHex " + preparedOffererDepositTxAsHex); log.debug("preparedOffererDepositTxAsHex " + preparedOffererDepositTxAsHex);
try try
{ {
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSign(takerAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, preparedOffererDepositTxAsHex); Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSign(takerInputAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, preparedOffererDepositTxAsHex);
log.debug("2.10 deposit tx created: " + signedTakerDepositTx); log.debug("2.10 deposit tx created: " + signedTakerDepositTx);
sendSignedTakerDepositTxAsHex(signedTakerDepositTx); sendSignedTakerDepositTxAsHex(signedTakerDepositTx);
} catch (InterruptedException | AddressFormatException | ExecutionException | InsufficientMoneyException e) } catch (InterruptedException | AddressFormatException | ExecutionException | InsufficientMoneyException e)
@ -433,9 +436,12 @@ public class TakerPaymentProtocol
String signedTakerDepositTxAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize()); String signedTakerDepositTxAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize());
String txScriptSigAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes()); 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()); String txConnOutAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize());
//TODO just 1 address supported yet
String payoutAddress = walletFacade.getAddressAsString();
log.debug("2.10 deposit txAsHex: " + signedTakerDepositTxAsHex); log.debug("2.10 deposit txAsHex: " + signedTakerDepositTxAsHex);
log.debug("2.10 txScriptSigAsHex: " + txScriptSigAsHex); log.debug("2.10 txScriptSigAsHex: " + txScriptSigAsHex);
log.debug("2.10 txConnOutAsHex: " + txConnOutAsHex); log.debug("2.10 txConnOutAsHex: " + txConnOutAsHex);
log.debug("2.10 payoutAddress: " + payoutAddress);
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_OFFERER_DEPOSIT_PUBLICATION, TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_OFFERER_DEPOSIT_PUBLICATION,
trade.getUid(), trade.getUid(),
@ -446,7 +452,8 @@ public class TakerPaymentProtocol
txScriptSigAsHex, txScriptSigAsHex,
txConnOutAsHex, txConnOutAsHex,
contractAsJson, contractAsJson,
signature); signature,
payoutAddress);
log.debug("2.11 sendTradingMessage"); log.debug("2.11 sendTradingMessage");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener); messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
@ -466,6 +473,9 @@ public class TakerPaymentProtocol
{ {
log.debug("3.6 DepositTxID received: " + tradeMessage.getDepositTxID()); log.debug("3.6 DepositTxID received: " + tradeMessage.getDepositTxID());
//Transaction tx = walletFacade.getWallet().getTransaction(new Sha256Hash(tradeMessage.getDepositTxID()));
//walletFacade.getWallet().commitTx(tx);
takerPaymentProtocolListener.onProgress(getProgress()); takerPaymentProtocolListener.onProgress(getProgress());
takerPaymentProtocolListener.onDepositTxPublished(tradeMessage.getDepositTxID()); takerPaymentProtocolListener.onDepositTxPublished(tradeMessage.getDepositTxID());
} }
@ -480,12 +490,10 @@ public class TakerPaymentProtocol
// Step 3.11 Incoming msg from offerer // Step 3.11 Incoming msg from offerer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void onBankTransferInited() public void onBankTransferInited(TradeMessage tradeMessage)
{ {
log.debug("3.11 Bank transfer inited msg received"); log.debug("3.11 Bank transfer inited msg received");
log.debug("########## LAST STEP TAKER FOR FIRST PART"); takerPaymentProtocolListener.onBankTransferInited(tradeMessage);
takerPaymentProtocolListener.onBankTransferInited();
} }
//************************************************************************************************ //************************************************************************************************
@ -493,6 +501,91 @@ public class TakerPaymentProtocol
//************************************************************************************************ //************************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.12 User clicked the "bank transfer received" button, so we release the funds for pay out
///////////////////////////////////////////////////////////////////////////////////////////
public void releaseBTC(TradeMessage tradeMessage)
{
log.debug("3.12 releaseBTC");
FutureCallback<Transaction> callback = new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
System.out.println("######### 3.12 onSuccess walletFacade.takerSignAndSendTx " + transaction.toString());
log.error("3.12 onSuccess walletFacade.takerSignAndSendTx " + transaction.toString());
takerPaymentProtocolListener.onTradeCompleted(transaction.getHashAsString());
sendPayoutTxToOfferer(transaction.getHashAsString());
}
@Override
public void onFailure(Throwable t)
{
log.error("######### 3.12 onFailure walletFacade.takerSignAndSendTx");
System.err.println("3.12 onFailure walletFacade.takerSignAndSendTx");
takerPaymentProtocolListener.onFailure("takerSignAndSendTx failed " + t.getMessage());
}
};
try
{
String depositTxID = tradeMessage.getDepositTxID();
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.takerSignAndSendTx");
walletFacade.takerSignAndSendTx(depositTxID,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
callback);
} catch (InsufficientMoneyException e)
{
log.error("3.12 offererCreateAndSignPayoutTx onFailed InsufficientMoneyException " + e.getMessage());
} catch (AddressFormatException e)
{
log.error("3.12 offererCreateAndSignPayoutTx onFailed AddressFormatException " + e.getMessage());
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Step 3.13 Send payout txID to offerer
///////////////////////////////////////////////////////////////////////////////////////////
public void sendPayoutTxToOfferer(String txId)
{
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!!!!!!!!!!!");
takerPaymentProtocolListener.onProgress(getProgress());
}
@Override
public void onFailed()
{
log.debug("3.13 sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onFailed");
takerPaymentProtocolListener.onFailure("sendPayoutTxToOfferer PAYOUT_TX_PUBLISHED onFailed");
}
};
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.PAYOUT_TX_PUBLISHED, trade.getUid());
tradeMessage.setPayoutTxID(txId);
log.debug("3.13 sendTradeMessage PAYOUT_TX_PUBLISHED");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
}
private double getProgress() private double getProgress()
{ {
currentStep++; currentStep++;

View file

@ -1,5 +1,7 @@
package io.bitsquare.trade.taker; package io.bitsquare.trade.taker;
import io.bitsquare.msg.TradeMessage;
public interface TakerPaymentProtocolListener public interface TakerPaymentProtocolListener
{ {
void onProgress(double progress); void onProgress(double progress);
@ -8,5 +10,7 @@ public interface TakerPaymentProtocolListener
void onDepositTxPublished(String depositTxID); void onDepositTxPublished(String depositTxID);
void onBankTransferInited(); void onBankTransferInited(TradeMessage tradeMessage);
void onTradeCompleted(String hashAsString);
} }

View file

@ -25,7 +25,7 @@ public class DSAKeyUtil
public static KeyPair getKeyPair(String keyName) public static KeyPair getKeyPair(String keyName)
{ {
return getKeyPair("public_" + keyName + ".key", "private_" + keyName + ".key"); return getKeyPair(keyName + "_public" + ".key", keyName + "_private" + ".key");
} }

View file

@ -15,17 +15,18 @@
<logger name="io.bitsquare" level="DEBUG"/> <logger name="io.bitsquare" level="DEBUG"/>
<logger name="com.google.bitcoin" level="ERROR"/> <logger name="com.google.bitcoin" level="INFO"/>
<logger name="net.tomp2p" level="ERROR"/> <logger name="net.tomp2p" level="WARN"/>
<logger name="com.google.bitcoin.core.Peer" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.core.PeerGroup" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.net.NioClientManager" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.net.ConnectionHandler" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.net.discovery.DnsDiscovery" level="OFF" additivity="false"/>
<!-- <!--
--> -->
<logger name="com.google.bitcoin.core.Peer" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.core.PeerGroup" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.core.PeerSocketHandler" level="OFF" additivity="false"/>
<logger name="com.google.bitcoin.net.NioClientManager" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.net.ConnectionHandler" level="ERROR" additivity="false"/>
<logger name="com.google.bitcoin.net.discovery.DnsDiscovery" level="OFF" additivity="false"/>
<logger name="com.google.bitcoin.core.MemoryPool" level="OFF" additivity="false"/>
</configuration> </configuration>