separate wallet addresses

This commit is contained in:
Manfred Karrer 2014-06-19 23:58:27 +02:00
parent 24fdb06a90
commit 205259bee9
34 changed files with 822 additions and 366 deletions

View File

@ -176,7 +176,14 @@
<artifactId>core</artifactId>
<version>1.50.0.0</version>
</dependency>
<!--
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard</artifactId>
<version>4.4</version>
<scope>runtime</scope>
</dependency>
-->
</dependencies>
<reporting>

View File

@ -0,0 +1,146 @@
package io.bitsquare.btc;
import com.google.bitcoin.core.*;
import com.google.bitcoin.params.RegTestParams;
import com.google.bitcoin.wallet.CoinSelection;
import com.google.bitcoin.wallet.DefaultCoinSelector;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.util.*;
/**
* This class implements a {@link com.google.bitcoin.wallet.CoinSelector} which attempts to get the highest priority
* possible. This means that the transaction is the most likely to get confirmed. Note that this means we may end up
* "spending" more priority than would be required to get the transaction we are creating confirmed.
*/
public class AddressBasedCoinSelector extends DefaultCoinSelector
{
private static final Logger log = LoggerFactory.getLogger(AddressBasedCoinSelector.class);
private String tradeUID;
private NetworkParameters params;
private AddressInfo addressInfo;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public AddressBasedCoinSelector()
{
}
public AddressBasedCoinSelector(NetworkParameters params, AddressInfo addressInfo)
{
this.params = params;
this.addressInfo = addressInfo;
}
public AddressBasedCoinSelector(String tradeUID)
{
this.tradeUID = tradeUID;
}
/**
* Sub-classes can override this to just customize whether transactions are usable, but keep age sorting.
*/
protected boolean shouldSelect(Transaction tx)
{
return isSelectable(tx);
}
protected boolean matchesRequiredAddress(TransactionOutput transactionOutput)
{
if (!ScriptUtil.isOpReturnScript(transactionOutput))
{
Address addressOutput = transactionOutput.getScriptPubKey().getToAddress(params);
if (addressInfo != null && addressOutput.equals(addressInfo.getAddress()))
{
return true;
}
}
return false;
}
public CoinSelection select(BigInteger biTarget, LinkedList<TransactionOutput> candidates)
{
long target = biTarget.longValue();
HashSet<TransactionOutput> selected = new HashSet<TransactionOutput>();
// Sort the inputs by age*value so we get the highest "coindays" spent.
// TODO: Consider changing the wallets internal format to track just outputs and keep them ordered.
ArrayList<TransactionOutput> sortedOutputs = new ArrayList<TransactionOutput>(candidates);
// When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
// them in order to improve performance.
if (!biTarget.equals(NetworkParameters.MAX_MONEY))
{
sortOutputs(sortedOutputs);
}
// Now iterate over the sorted outputs until we have got as close to the target as possible or a little
// bit over (excessive value will be change).
long total = 0;
for (TransactionOutput output : sortedOutputs)
{
if (total >= target) break;
// Only pick chain-included transactions, or transactions that are ours and pending.
// Only select outputs from our defined address(es)
if (!shouldSelect(output.getParentTransaction()) || !matchesRequiredAddress(output))
continue;
selected.add(output);
total += output.getValue().longValue();
}
// Total may be lower than target here, if the given candidates were insufficient to create to requested
// transaction.
return new CoinSelection(BigInteger.valueOf(total), selected);
}
@VisibleForTesting
static void sortOutputs(ArrayList<TransactionOutput> outputs)
{
Collections.sort(outputs, new Comparator<TransactionOutput>()
{
public int compare(TransactionOutput a, TransactionOutput b)
{
int depth1 = 0;
int depth2 = 0;
TransactionConfidence conf1 = a.getParentTransaction().getConfidence();
TransactionConfidence conf2 = b.getParentTransaction().getConfidence();
if (conf1.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
depth1 = conf1.getDepthInBlocks();
if (conf2.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
depth2 = conf2.getDepthInBlocks();
BigInteger aValue = a.getValue();
BigInteger bValue = b.getValue();
BigInteger aCoinDepth = aValue.multiply(BigInteger.valueOf(depth1));
BigInteger bCoinDepth = bValue.multiply(BigInteger.valueOf(depth2));
int c1 = bCoinDepth.compareTo(aCoinDepth);
if (c1 != 0) return c1;
// The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size.
int c2 = bValue.compareTo(aValue);
if (c2 != 0) return c2;
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
BigInteger aHash = a.getParentTransaction().getHash().toBigInteger();
BigInteger bHash = b.getParentTransaction().getHash().toBigInteger();
return aHash.compareTo(bHash);
}
});
}
public static boolean isSelectable(Transaction tx)
{
// Only pick chain-included transactions, or transactions that are ours and pending.
TransactionConfidence confidence = tx.getConfidence();
TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
confidence.getSource().equals(TransactionConfidence.Source.SELF) &&
// In regtest mode we expect to have only one peer, so we won't see transactions propagate.
// TODO: The value 1 below dates from a time when transactions we broadcast *to* were counted, set to 0
(confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get());
}
}

View File

@ -5,21 +5,33 @@ import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.NetworkParameters;
import com.google.bitcoin.core.Utils;
import java.beans.Transient;
import java.io.Serializable;
public class AddressInfo implements Serializable
{
private static final long serialVersionUID = 5501603992599920416L;
public static enum AddressContext
{
REGISTRATION_FEE,
CREATE_OFFER_FEE,
TAKE_OFFER_FEE,
TRADE,
ARBITRATOR_DEPOSIT
}
private ECKey key;
private NetworkParameters params;
private String label;
private String tradeId = null;
public AddressInfo(ECKey key, NetworkParameters params, String label)
private AddressContext addressContext;
public AddressInfo(ECKey key, NetworkParameters params, AddressContext addressContext, String label)
{
this.key = key;
this.params = params;
this.addressContext = addressContext;
this.label = label;
}
@ -28,11 +40,27 @@ public class AddressInfo implements Serializable
this.label = label;
}
public void setTradeId(String tradeId)
{
this.tradeId = tradeId;
}
public String getTradeId()
{
return tradeId;
}
public String getLabel()
{
return label;
}
public AddressContext getAddressContext()
{
return addressContext;
}
public String getAddressString()
{
return getAddress().toString();
@ -43,13 +71,11 @@ public class AddressInfo implements Serializable
return Utils.bytesToHexString(key.getPubKey());
}
@Transient
public ECKey getKey()
{
return key;
}
@Transient
public Address getAddress()
{
return key.toAddress(params);

View File

@ -3,12 +3,18 @@ package io.bitsquare.btc;
import com.google.bitcoin.core.NetworkParameters;
import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.crypto.KeyCrypter;
import com.google.bitcoin.wallet.CoinSelector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BitSquareWallet extends Wallet
import java.io.Serializable;
public class BitSquareWallet extends Wallet implements Serializable
{
private static final Logger log = LoggerFactory.getLogger(BitSquareWallet.class);
private static final long serialVersionUID = -6231929674475881549L;
private transient CoinSelector coinSelector = new AddressBasedCoinSelector();
public BitSquareWallet(NetworkParameters params)
{
@ -20,4 +26,5 @@ public class BitSquareWallet extends Wallet
super(params, keyCrypter);
}
}

View File

@ -18,6 +18,12 @@ public class BtcFormatter
public static BigInteger BTC = new BigInteger("100000000");
public static BigInteger mBTC = new BigInteger("100000");
public static String btcToString(BigInteger value)
{
return Utils.bitcoinValueToFriendlyString(value);
}
//TODO
public static double satoshiToBTC(BigInteger satoshis)
{

View File

@ -0,0 +1,55 @@
package io.bitsquare.btc;
import com.google.bitcoin.core.*;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
public class FeePolicy
{
private static final Logger log = LoggerFactory.getLogger(FeePolicy.class);
public static BigInteger TX_FEE = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
public static BigInteger ACCOUNT_REGISTRATION_FEE = Utils.toNanoCoins("0.01");
public static BigInteger CREATE_OFFER_FEE = Utils.toNanoCoins("0.001");
public static BigInteger TAKE_OFFER_FEE = CREATE_OFFER_FEE;
private static final String registrationFee = "mvkDXt4QmN4Nq9dRUsRigBCaovde9nLkZR";
private static final String offerFee = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg";
private final NetworkParameters params;
@Inject
public FeePolicy(NetworkParameters params)
{
this.params = params;
}
//TODO
public Address getAddressForRegistrationFee()
{
try
{
return new Address(params, registrationFee);
} catch (AddressFormatException e)
{
e.printStackTrace();
return null;
}
}
//TODO
public Address getAddressForOfferFee()
{
try
{
return new Address(params, offerFee);
} catch (AddressFormatException e)
{
e.printStackTrace();
return null;
}
}
}

View File

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

View File

@ -9,11 +9,14 @@ import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
public class ScriptUtil
{
public static Script getEmptyOP_RETURNScript()
public static Script getOpReturnScript()
{
return new ScriptBuilder()
.op(OP_RETURN)
.build();
return new ScriptBuilder().op(OP_RETURN).build();
}
public static Script getOpReturnScriptWithData(byte[] data)
{
return new ScriptBuilder().op(OP_RETURN).data(data).build();
}
public static boolean isOpReturnScript(TransactionOutput transactionOutput)

View File

@ -7,7 +7,10 @@ import com.google.bitcoin.params.RegTestParams;
import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptBuilder;
import com.google.bitcoin.utils.Threading;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@ -22,12 +25,11 @@ import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ExecutionException;
import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
public class WalletFacade
{
public static final String MAIN_NET = "MAIN_NET";
@ -40,6 +42,7 @@ public class WalletFacade
private NetworkParameters params;
private BitSquareWalletAppKit walletAppKit;
private FeePolicy feePolicy;
private CryptoFacade cryptoFacade;
private Storage storage;
private BitSquareWallet wallet;
@ -55,10 +58,11 @@ public class WalletFacade
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public WalletFacade(NetworkParameters params, BitSquareWalletAppKit walletAppKit, CryptoFacade cryptoFacade, Storage storage)
public WalletFacade(NetworkParameters params, BitSquareWalletAppKit walletAppKit, FeePolicy feePolicy, CryptoFacade cryptoFacade, Storage storage)
{
this.params = params;
this.walletAppKit = walletAppKit;
this.feePolicy = feePolicy;
this.cryptoFacade = cryptoFacade;
this.storage = storage;
}
@ -123,6 +127,7 @@ public class WalletFacade
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{
log.debug("onTransactionConfidenceChanged " + tx.getConfidence());
notifyConfidenceListeners(tx);
}
@ -162,8 +167,14 @@ public class WalletFacade
}
else
{
addressInfoList.add(getRegistrationAddressInfo());
storage.write("addressInfoList", addressInfoList);
ECKey registrationKey = wallet.getKeys().get(0);
AddressInfo registrationAddressInfo = new AddressInfo(registrationKey, params, AddressInfo.AddressContext.REGISTRATION_FEE, "Registration");
addressInfoList.add(registrationAddressInfo);
saveAddressInfoList();
getNewOfferFeeAddressInfo();
getNewTakerFeeAddressInfo();
getNewTradeAddressInfo();
}
}
@ -180,6 +191,12 @@ public class WalletFacade
return wallet;
}
private void saveAddressInfoList()
{
// use wallet extension?
storage.write("addressInfoList", addressInfoList);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Listener
@ -250,7 +267,7 @@ public class WalletFacade
Address address = transactionOutput.getScriptPubKey().getToAddress(params);
if (address.equals(balanceListener.getAddress()))
{
balanceListener.onBalanceChanged(getBalance(address));
balanceListener.onBalanceChanged(getBalanceForAddress(address));
}
}
}
@ -259,7 +276,7 @@ public class WalletFacade
///////////////////////////////////////////////////////////////////////////////////////////
// Address management
// Get AddressInfo objects
///////////////////////////////////////////////////////////////////////////////////////////
public List<AddressInfo> getAddressInfoList()
@ -269,26 +286,123 @@ public class WalletFacade
public AddressInfo getRegistrationAddressInfo()
{
ECKey registrationKey = wallet.getKeys().get(0);
return new AddressInfo(registrationKey, params, "Registration");
return getAddressInfoByAddressContext(AddressInfo.AddressContext.REGISTRATION_FEE);
}
public AddressInfo getNewAddressInfo(String label)
public AddressInfo getCreateOfferFeeAddressInfo()
{
ECKey key = new ECKey();
wallet.addKey(key);
AddressInfo addressInfo = new AddressInfo(key, params, label);
addressInfoList.add(addressInfo);
storage.write("addressInfoList", addressInfoList);
return getAddressInfoByAddressContext(AddressInfo.AddressContext.CREATE_OFFER_FEE);
}
public AddressInfo getTakerFeeAddressInfo()
{
return getAddressInfoByAddressContext(AddressInfo.AddressContext.TAKE_OFFER_FEE);
}
public AddressInfo getArbitratorDepositAddressInfo()
{
AddressInfo arbitratorDepositAddressInfo = getAddressInfoByAddressContext(AddressInfo.AddressContext.ARBITRATOR_DEPOSIT);
if (arbitratorDepositAddressInfo == null)
arbitratorDepositAddressInfo = getNewArbitratorDepositAddressInfo();
return arbitratorDepositAddressInfo;
}
private AddressInfo getUnusedTradeAddressInfo()
{
if (addressInfoList != null)
{
List<AddressInfo> filteredList = Lists.newArrayList(Collections2.filter(addressInfoList, new Predicate<AddressInfo>()
{
@Override
public boolean apply(@Nullable AddressInfo addressInfo)
{
return (addressInfo != null && addressInfo.getAddressContext().equals(AddressInfo.AddressContext.TRADE) && addressInfo.getTradeId() == null);
}
}));
if (filteredList != null && filteredList.size() > 0)
return filteredList.get(0);
else
return null;
}
return null;
}
private AddressInfo getAddressInfoByAddressContext(AddressInfo.AddressContext addressContext)
{
if (addressInfoList != null)
{
List<AddressInfo> filteredList = Lists.newArrayList(Collections2.filter(addressInfoList, new Predicate<AddressInfo>()
{
@Override
public boolean apply(@Nullable AddressInfo addressInfo)
{
return (addressInfo != null && addressContext != null && addressInfo.getAddressContext() != null && addressInfo.getAddressContext().equals(addressContext));
}
}));
if (filteredList != null && filteredList.size() > 0)
return filteredList.get(0);
else
return null;
}
return null;
}
public AddressInfo getAddressInfoByTradeID(String tradeId)
{
for (AddressInfo addressInfo : addressInfoList)
{
if (addressInfo.getTradeId() != null && addressInfo.getTradeId().equals(tradeId))
return addressInfo;
}
AddressInfo addressInfo = getUnusedTradeAddressInfo();
addressInfo.setTradeId(tradeId);
return addressInfo;
}
public AddressInfo getNewArbitratorAddressInfo()
///////////////////////////////////////////////////////////////////////////////////////////
// Create new AddressInfo objects
///////////////////////////////////////////////////////////////////////////////////////////
public AddressInfo getNewTradeAddressInfo()
{
return getNewAddressInfo("Arbitrator deposit");
return getNewAddressInfo(AddressInfo.AddressContext.TRADE, "New trade");
}
public TransactionConfidence getConfidence(Address address)
private AddressInfo getNewAddressInfo(AddressInfo.AddressContext addressContext, String label)
{
ECKey key = new ECKey();
wallet.addKey(key);
AddressInfo addressInfo = new AddressInfo(key, params, addressContext, label);
addressInfoList.add(addressInfo);
saveAddressInfoList();
return addressInfo;
}
private AddressInfo getNewOfferFeeAddressInfo()
{
return getNewAddressInfo(AddressInfo.AddressContext.CREATE_OFFER_FEE, "Create offer fee");
}
private AddressInfo getNewTakerFeeAddressInfo()
{
return getNewAddressInfo(AddressInfo.AddressContext.TAKE_OFFER_FEE, "Take offer fee");
}
private AddressInfo getNewArbitratorDepositAddressInfo()
{
return getNewAddressInfo(AddressInfo.AddressContext.ARBITRATOR_DEPOSIT, "Arbitrator deposit");
}
///////////////////////////////////////////////////////////////////////////////////////////
// TransactionConfidence
///////////////////////////////////////////////////////////////////////////////////////////
public TransactionConfidence getConfidenceForAddress(Address address)
{
Set<Transaction> transactions = wallet.getTransactions(true);
if (transactions != null)
@ -317,7 +431,12 @@ public class WalletFacade
return null;
}
public BigInteger getBalance(Address address)
///////////////////////////////////////////////////////////////////////////////////////////
// Balance
///////////////////////////////////////////////////////////////////////////////////////////
public BigInteger getBalanceForAddress(Address address)
{
LinkedList<TransactionOutput> all = wallet.calculateAllSpendCandidates(false);
BigInteger value = BigInteger.ZERO;
@ -342,103 +461,21 @@ public class WalletFacade
public BigInteger getRegistrationBalance()
{
return getBalance(getRegistrationAddressInfo().getAddress());
return getBalanceForAddress(getRegistrationAddressInfo().getAddress());
}
public ECKey getRegistrationKey()
public BigInteger getArbitratorDepositBalance()
{
return getRegistrationAddressInfo().getKey();
return getBalanceForAddress(getArbitratorDepositAddressInfo().getAddress());
}
///////////////////////////////////////////////////////////////////////////////////////////
// TODO
///////////////////////////////////////////////////////////////////////////////////////////
//TODO
public String getTradingAddress()
{
return getTradingKey().toAddress(params).toString();
}
//TODO
public String getPubKeyAsHex()
{
return Utils.bytesToHexString(getTradingKey().getPubKey());
}
//TODO
public ECKey getTradingKey()
{
return wallet.getKeys().get(1);
}
//TODO separate wallets
public BigInteger getCollateralBalance()
{
return wallet.getBalance(Wallet.BalanceType.ESTIMATED);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Account registration
///////////////////////////////////////////////////////////////////////////////////////////
public void publishRegistrationTxWithExtraData(String stringifiedBankAccounts) throws InsufficientMoneyException
{
log.debug("publishRegistrationTxWithExtraData");
log.trace("inputs: ");
log.trace("stringifiedBankAccounts " + stringifiedBankAccounts);
byte[] dataToEmbed = cryptoFacade.getEmbeddedAccountRegistrationData(getRegistrationKey(), stringifiedBankAccounts);
Script script = new ScriptBuilder().op(OP_RETURN).data(dataToEmbed).build();
Transaction tx = new Transaction(params);
TransactionOutput dataOutput = new TransactionOutput(params, tx, Transaction.MIN_NONDUST_OUTPUT, script.getProgram());
tx.addOutput(dataOutput);
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
// give fee to miners yet. Later it could be spent to other traders via lottery...
sendRequest.fee = Fees.ACCOUNT_REGISTRATION_FEE.subtract(Transaction.MIN_NONDUST_OUTPUT).subtract(Fees.TX_FEE);
log.trace("sendRequest.fee: " + Utils.bitcoinValueToFriendlyString(sendRequest.fee));
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
log.debug("Registration transaction: " + tx.toString());
printInputs("publishRegistrationTxWithExtraData", tx);
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction result)
{
log.debug("sendResult onSuccess");
}
@Override
public void onFailure(Throwable t)
{
log.error("sendResult onFailure:" + t.toString());
}
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// Trade process
///////////////////////////////////////////////////////////////////////////////////////////
//TODO refactor to similar solution like in PaymentChannelServerState
public String payOfferFee(BigInteger fee, FutureCallback<Transaction> callback) throws InsufficientMoneyException
{
log.debug("payOfferFee fee=" + Utils.bitcoinValueToFriendlyString(fee));
Transaction tx = new Transaction(params);
tx.addOutput(Transaction.MIN_NONDUST_OUTPUT, ScriptUtil.getEmptyOP_RETURNScript());
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.fee = fee.subtract(Transaction.MIN_NONDUST_OUTPUT).subtract(Fees.TX_FEE);
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, callback);
log.debug("Check if wallet is consistent: result=" + wallet.isConsistent());
printInputs("payOfferFee", tx);
log.debug("tx=" + tx.toString());
return tx.getHashAsString();
}
public int getNumOfPeersSeenTx(String txID)
{
// TODO check from blockchain
@ -447,13 +484,84 @@ public class WalletFacade
}
///////////////////////////////////////////////////////////////////////////////////////////
// Transactions
///////////////////////////////////////////////////////////////////////////////////////////
public void payRegistrationFee(String stringifiedBankAccounts, FutureCallback<Transaction> callback) throws InsufficientMoneyException
{
log.debug("payRegistrationFee");
log.trace("stringifiedBankAccounts " + stringifiedBankAccounts);
Transaction tx = new Transaction(params);
byte[] dataToEmbed = cryptoFacade.getEmbeddedAccountRegistrationData(getRegistrationAddressInfo().getKey(), stringifiedBankAccounts);
tx.addOutput(Transaction.MIN_NONDUST_OUTPUT, ScriptUtil.getOpReturnScriptWithData(dataToEmbed));
BigInteger fee = FeePolicy.ACCOUNT_REGISTRATION_FEE.subtract(Transaction.MIN_NONDUST_OUTPUT).subtract(FeePolicy.TX_FEE);
log.trace("fee: " + BtcFormatter.btcToString(fee));
tx.addOutput(fee, feePolicy.getAddressForRegistrationFee());
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.coinSelector = new AddressBasedCoinSelector(params, getRegistrationAddressInfo());
sendRequest.changeAddress = getRegistrationAddressInfo().getAddress();
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, callback);
log.debug("Registration transaction: " + tx.toString());
printInputs("payRegistrationFee", tx);
}
public String payCreateOfferFee(FutureCallback<Transaction> callback) throws InsufficientMoneyException
{
Transaction tx = new Transaction(params);
BigInteger fee = FeePolicy.CREATE_OFFER_FEE.subtract(FeePolicy.TX_FEE);
log.trace("fee: " + BtcFormatter.btcToString(fee));
tx.addOutput(fee, feePolicy.getAddressForOfferFee());
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.coinSelector = new AddressBasedCoinSelector(params, getCreateOfferFeeAddressInfo());
sendRequest.changeAddress = getCreateOfferFeeAddressInfo().getAddress();
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, callback);
printInputs("payTakeOfferFee", tx);
log.debug("tx=" + tx.toString());
return tx.getHashAsString();
}
public String payTakeOfferFee(FutureCallback<Transaction> callback) throws InsufficientMoneyException
{
Transaction tx = new Transaction(params);
BigInteger fee = FeePolicy.TAKE_OFFER_FEE.subtract(FeePolicy.TX_FEE);
log.trace("fee: " + BtcFormatter.btcToString(fee));
tx.addOutput(fee, feePolicy.getAddressForOfferFee());
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.coinSelector = new AddressBasedCoinSelector(params, getTakerFeeAddressInfo());
sendRequest.changeAddress = getTakerFeeAddressInfo().getAddress();
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, callback);
printInputs("payTakeOfferFee", tx);
log.debug("tx=" + tx.toString());
return tx.getHashAsString();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Trade process
///////////////////////////////////////////////////////////////////////////////////////////
// 1. step: deposit tx
// Offerer creates the 2of3 multiSig deposit tx with his unsigned input and change output
public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererInputAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey) throws InsufficientMoneyException
public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererInputAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey, String tradeId) throws InsufficientMoneyException
{
log.debug("offererCreatesMSTxAndAddPayment");
log.trace("inputs: ");
log.trace("offererInputAmount=" + Utils.bitcoinValueToFriendlyString(offererInputAmount));
log.trace("offererInputAmount=" + BtcFormatter.btcToString(offererInputAmount));
log.trace("offererPubKey=" + offererPubKey);
log.trace("takerPubKey=" + takerPubKey);
log.trace("arbitratorPubKey=" + arbitratorPubKey);
@ -467,7 +575,13 @@ public class WalletFacade
Transaction tx = new Transaction(params);
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
tx.addOutput(offererInputAmount, multiSigOutputScript);
wallet.completeTx(Wallet.SendRequest.forTx(tx));
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
AddressInfo addressInfo = getAddressInfoByTradeID(tradeId);
addressInfo.setTradeId(tradeId);
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressInfo);
sendRequest.changeAddress = addressInfo.getAddress();
wallet.completeTx(sendRequest);
// The completeTx() call signs the input, but we don't want to pass over a signed tx so we remove the
// signature to make sure the tx is invalid for publishing
@ -497,13 +611,14 @@ public class WalletFacade
String offererPubKey,
String takerPubKey,
String arbitratorPubKey,
String offerersPartialDepositTxAsHex
String offerersPartialDepositTxAsHex,
String tradeId
) throws InsufficientMoneyException, ExecutionException, InterruptedException, AddressFormatException
{
log.debug("takerAddPaymentAndSignTx");
log.trace("inputs: ");
log.trace("takerInputAmount=" + Utils.bitcoinValueToFriendlyString(takerInputAmount));
log.trace("msOutputAmount=" + Utils.bitcoinValueToFriendlyString(msOutputAmount));
log.trace("takerInputAmount=" + BtcFormatter.btcToString(takerInputAmount));
log.trace("msOutputAmount=" + BtcFormatter.btcToString(msOutputAmount));
log.trace("offererPubKey=" + offererPubKey);
log.trace("takerPubKey=" + takerPubKey);
log.trace("arbitratorPubKey=" + arbitratorPubKey);
@ -518,7 +633,14 @@ public class WalletFacade
Transaction tempTx = new Transaction(params);
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
tempTx.addOutput(takerInputAmount, multiSigOutputScript);
wallet.completeTx(Wallet.SendRequest.forTx(tempTx));
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tempTx);
AddressInfo addressInfo = getAddressInfoByTradeID(tradeId);
addressInfo.setTradeId(tradeId);
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressInfo);
sendRequest.changeAddress = addressInfo.getAddress();
wallet.completeTx(sendRequest);
printInputs("tempTx", tempTx);
log.trace("tempTx=" + tempTx);
// That tx has signed input, but we don't need to remove it as we don't send that tx out, it is just used temporary.
@ -550,7 +672,7 @@ public class WalletFacade
tx.addOutput(tempTx.getOutput(1));
// We add the btc tx fee to the msOutputAmount and apply the change to the multiSig output
msOutputAmount = msOutputAmount.add(Fees.TX_FEE);
msOutputAmount = msOutputAmount.add(FeePolicy.TX_FEE);
tx.getOutput(0).setValue(msOutputAmount);
// Now we sign our input
@ -602,6 +724,8 @@ public class WalletFacade
String takersSignedTxAsHex,
String takersSignedConnOutAsHex,
String takersSignedScriptSigAsHex,
long offererTxOutIndex,
long takerTxOutIndex,
FutureCallback<Transaction> callback) throws Exception
{
log.debug("offererSignAndPublishTx");
@ -624,9 +748,9 @@ public class WalletFacade
// add input
Transaction offerersFirstTxConnOut = wallet.getTransaction(offerersFirstTx.getInput(0).getOutpoint().getHash()); // pass that around!
TransactionOutPoint offerersFirstTxOutPoint = new TransactionOutPoint(params, 1, offerersFirstTxConnOut);
TransactionOutPoint offerersFirstTxOutPoint = new TransactionOutPoint(params, offererTxOutIndex, offerersFirstTxConnOut);
//TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, offerersFirstTx.getInput(0).getScriptBytes(), offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes aray
TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, new byte[]{}, offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes aray
TransactionInput offerersFirstTxInput = new TransactionInput(params, tx, new byte[]{}, offerersFirstTxOutPoint); // pass that around! getScriptBytes = empty bytes array
offerersFirstTxInput.setParent(tx);
tx.addInput(offerersFirstTxInput);
@ -638,7 +762,7 @@ public class WalletFacade
// add input
Transaction takersSignedTxConnOut = new Transaction(params, Utils.parseAsHexOrBase58(takersSignedConnOutAsHex));
TransactionOutPoint takersSignedTxOutPoint = new TransactionOutPoint(params, 1, takersSignedTxConnOut);
TransactionOutPoint takersSignedTxOutPoint = new TransactionOutPoint(params, takerTxOutIndex, takersSignedTxConnOut);
TransactionInput takersSignedTxInput = new TransactionInput(params, tx, Utils.parseAsHexOrBase58(takersSignedScriptSigAsHex), takersSignedTxOutPoint);
takersSignedTxInput.setParent(tx);
tx.addInput(takersSignedTxInput);
@ -672,13 +796,13 @@ public class WalletFacade
else
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
log.trace("check if it can be correctly spent for input 0");
input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false);
log.trace("check if it can be correctly spent for input 0 OK");
log.trace("check if it can be correctly spent for input 1");
TransactionInput input1 = tx.getInput(1);
scriptPubKey = input1.getConnectedOutput().getScriptPubKey();
input1.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false);
log.trace("check if it can be correctly spent for input 1 OK");
/*
IN[0] offerer signed 0.1001
@ -736,13 +860,14 @@ public class WalletFacade
public Pair<ECKey.ECDSASignature, String> offererCreatesAndSignsPayoutTx(String depositTxID,
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String takerAddress) throws InsufficientMoneyException, AddressFormatException
String takerAddress,
String tradeID) throws InsufficientMoneyException, AddressFormatException
{
log.debug("offererCreatesAndSignsPayoutTx");
log.trace("inputs: ");
log.trace("depositTxID=" + depositTxID);
log.trace("offererPaybackAmount=" + Utils.bitcoinValueToFriendlyString(offererPaybackAmount));
log.trace("takerPaybackAmount=" + Utils.bitcoinValueToFriendlyString(takerPaybackAmount));
log.trace("offererPaybackAmount=" + BtcFormatter.btcToString(offererPaybackAmount));
log.trace("takerPaybackAmount=" + BtcFormatter.btcToString(takerPaybackAmount));
log.trace("takerAddress=" + takerAddress);
// Offerer has published depositTx earlier, so he has it in his wallet
@ -750,13 +875,13 @@ public class WalletFacade
String depositTxAsHex = Utils.bytesToHexString(depositTx.bitcoinSerialize());
// We create the payout tx
Transaction tx = createPayoutTx(depositTxAsHex, offererPaybackAmount, takerPaybackAmount, getTradingAddress(), takerAddress);
Transaction tx = createPayoutTx(depositTxAsHex, offererPaybackAmount, takerPaybackAmount, getAddressInfoByTradeID(tradeID).getAddressString(), takerAddress);
// We create the signature for that tx
TransactionOutput multiSigOutput = tx.getInput(0).getConnectedOutput();
Script multiSigScript = multiSigOutput.getScriptPubKey();
Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = getTradingKey().sign(sigHash);
ECKey.ECDSASignature offererSignature = getAddressInfoByTradeID(tradeID).getKey().sign(sigHash);
TransactionSignature offererTxSig = new TransactionSignature(offererSignature, Transaction.SigHash.ALL, false);
Script inputScript = ScriptBuilder.createMultiSigInputScript(ImmutableList.of(offererTxSig));
@ -773,6 +898,7 @@ public class WalletFacade
BigInteger offererPaybackAmount,
BigInteger takerPaybackAmount,
String offererAddress,
String tradeID,
FutureCallback<Transaction> callback) throws InsufficientMoneyException, AddressFormatException
{
log.debug("takerSignsAndSendsTx");
@ -780,13 +906,13 @@ public class WalletFacade
log.trace("depositTxAsHex=" + depositTxAsHex);
log.trace("offererSignatureR=" + offererSignatureR);
log.trace("offererSignatureS=" + offererSignatureS);
log.trace("offererPaybackAmount=" + Utils.bitcoinValueToFriendlyString(offererPaybackAmount));
log.trace("takerPaybackAmount=" + Utils.bitcoinValueToFriendlyString(takerPaybackAmount));
log.trace("offererPaybackAmount=" + BtcFormatter.btcToString(offererPaybackAmount));
log.trace("takerPaybackAmount=" + BtcFormatter.btcToString(takerPaybackAmount));
log.trace("offererAddress=" + offererAddress);
log.trace("callback=" + callback.toString());
// We create the payout tx
Transaction tx = createPayoutTx(depositTxAsHex, offererPaybackAmount, takerPaybackAmount, offererAddress, getTradingAddress());
Transaction tx = createPayoutTx(depositTxAsHex, offererPaybackAmount, takerPaybackAmount, offererAddress, getAddressInfoByTradeID(tradeID).getAddressString());
// We sign that tx with our key and apply the signature form the offerer
TransactionOutput multiSigOutput = tx.getInput(0).getConnectedOutput();
@ -794,7 +920,7 @@ public class WalletFacade
Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
log.trace("sigHash=" + sigHash.toString());
ECKey.ECDSASignature takerSignature = getTradingKey().sign(sigHash);
ECKey.ECDSASignature takerSignature = getAddressInfoByTradeID(tradeID).getKey().sign(sigHash);
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = new ECKey.ECDSASignature(new BigInteger(offererSignatureR), new BigInteger(offererSignatureS));
@ -846,8 +972,8 @@ public class WalletFacade
log.trace("createPayoutTx");
log.trace("inputs: ");
log.trace("depositTxAsHex=" + depositTxAsHex);
log.trace("offererPaybackAmount=" + Utils.bitcoinValueToFriendlyString(offererPaybackAmount));
log.trace("takerPaybackAmount=" + Utils.bitcoinValueToFriendlyString(takerPaybackAmount));
log.trace("offererPaybackAmount=" + BtcFormatter.btcToString(offererPaybackAmount));
log.trace("takerPaybackAmount=" + BtcFormatter.btcToString(takerPaybackAmount));
log.trace("offererAddress=" + offererAddress);
log.trace("takerAddress=" + takerAddress);
@ -865,7 +991,7 @@ public class WalletFacade
{
for (TransactionInput input : tx.getInputs())
if (input.getConnectedOutput() != null)
log.trace(tracePrefix + ": " + Utils.bitcoinValueToFriendlyString(input.getConnectedOutput().getValue()));
log.trace(tracePrefix + ": " + BtcFormatter.btcToString(input.getConnectedOutput().getValue()));
else
log.trace(tracePrefix + ": " + "Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
}

View File

@ -12,6 +12,7 @@ import com.google.inject.name.Named;
import com.google.inject.name.Names;
import io.bitsquare.btc.BitSquareWalletAppKit;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
@ -39,6 +40,8 @@ public class BitSquareModule extends AbstractModule
bind(CryptoFacade.class).asEagerSingleton();
bind(WalletFacade.class).asEagerSingleton();
bind(FeePolicy.class).asEagerSingleton();
bind(BlockChainFacade.class).asEagerSingleton();
bind(MessageFacade.class).asEagerSingleton();

View File

@ -1,6 +1,9 @@
package io.bitsquare.gui;
import com.google.bitcoin.core.*;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.core.WalletEventListener;
import com.google.bitcoin.script.Script;
import com.google.inject.Inject;
import io.bitsquare.bank.BankAccount;
@ -123,8 +126,8 @@ public class MainController implements Initializable, NavigationController
//homeButton.fire();
//settingsButton.fire();
fundsButton.fire();
// sellButton.fire();
//fundsButton.fire();
sellButton.fire();
// ordersButton.fire();
// homeButton.fire();
// msgButton.fire();
@ -334,31 +337,31 @@ public class MainController implements Initializable, NavigationController
vBox.getChildren().setAll(hBox, titleLabel);
parent.getChildren().add(vBox);
balanceTextField.setText(Utils.bitcoinValueToFriendlyString(walletFacade.getWalletBalance()));
balanceTextField.setText(BtcFormatter.btcToString(walletFacade.getWalletBalance()));
walletFacade.getWallet().addEventListener(new WalletEventListener()
{
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{
balanceTextField.setText(Utils.bitcoinValueToFriendlyString(newBalance));
balanceTextField.setText(BtcFormatter.btcToString(newBalance));
}
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{
balanceTextField.setText(Utils.bitcoinValueToFriendlyString(walletFacade.getWallet().getBalance()));
balanceTextField.setText(BtcFormatter.btcToString(walletFacade.getWallet().getBalance()));
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
{
balanceTextField.setText(Utils.bitcoinValueToFriendlyString(newBalance));
balanceTextField.setText(BtcFormatter.btcToString(newBalance));
}
@Override
public void onReorganize(Wallet wallet)
{
balanceTextField.setText(Utils.bitcoinValueToFriendlyString(walletFacade.getWallet().getBalance()));
balanceTextField.setText(BtcFormatter.btcToString(walletFacade.getWallet().getBalance()));
}
@Override

View File

@ -371,8 +371,8 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
});
confidenceDisplay = new ConfidenceDisplay(walletFacade.getWallet(), confirmationLabel, balanceTextField, progressIndicator);
paymentDoneButton.setDisable(walletFacade.getCollateralBalance().compareTo(BigInteger.ZERO) == 0);
log.debug("getCollateralBalance " + walletFacade.getCollateralBalance().toString());
paymentDoneButton.setDisable(walletFacade.getArbitratorDepositBalance().compareTo(BigInteger.ZERO) == 0);
log.debug("getArbitratorDepositBalance " + walletFacade.getArbitratorDepositBalance().toString());
walletFacade.getWallet().addEventListener(new WalletEventListener()
{
@Override
@ -464,7 +464,7 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
BitSquareValidator.resetTextFields(hasDoubleValueTextFields);
BitSquareValidator.textFieldsHasDoubleValue(hasDoubleValueTextFields);
String pubKeyAsHex = walletFacade.getNewArbitratorAddressInfo().getPubKeyAsHexString();
String pubKeyAsHex = walletFacade.getArbitratorDepositAddressInfo().getPubKeyAsHexString();
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey());
String name = nameTextField.getText();

View File

@ -5,6 +5,9 @@ import javafx.scene.layout.Pane;
public class HSpacer extends Pane
{
public HSpacer()
{
}
public HSpacer(double width)
{

View File

@ -4,6 +4,10 @@ import javafx.scene.control.ScrollPane;
public class NoFocusScrollPane extends ScrollPane
{
public NoFocusScrollPane()
{
}
public void requestFocus()
{
// prevent focus

View File

@ -5,6 +5,9 @@ import javafx.scene.layout.Pane;
public class VSpacer extends Pane
{
public VSpacer()
{
}
public VSpacer(double height)
{

View File

@ -1,11 +1,11 @@
package io.bitsquare.gui.funds;
import com.google.bitcoin.core.TransactionConfidence;
import com.google.bitcoin.core.Utils;
import com.google.inject.Inject;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.btc.AddressInfo;
import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.listeners.ConfidenceListener;
@ -31,7 +31,6 @@ import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
public class FundsController implements Initializable, ChildController
{
private static final Logger log = LoggerFactory.getLogger(FundsController.class);
@ -105,9 +104,9 @@ public class FundsController implements Initializable, ChildController
///////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void onAddNewAddress(ActionEvent actionEvent)
public void onAddNewTradeAddress(ActionEvent actionEvent)
{
AddressInfo addressInfo = walletFacade.getNewAddressInfo("New address");
AddressInfo addressInfo = walletFacade.getNewTradeAddressInfo();
addressList.add(new AddressListItem(addressInfo.getLabel(), addressInfo.getAddress(), false));
}
@ -147,7 +146,7 @@ public class FundsController implements Initializable, ChildController
}
});
updateBalance(walletFacade.getBalance(item.getAddress()), balanceLabel);
updateBalance(walletFacade.getBalanceForAddress(item.getAddress()), balanceLabel);
setGraphic(balanceLabel);
}
else
@ -243,7 +242,7 @@ public class FundsController implements Initializable, ChildController
}
});
updateConfidence(walletFacade.getConfidence(item.getAddress()), progressIndicator, tooltip);
updateConfidence(walletFacade.getConfidenceForAddress(item.getAddress()), progressIndicator, tooltip);
setGraphic(progressIndicator);
}
else
@ -262,7 +261,7 @@ public class FundsController implements Initializable, ChildController
private void updateBalance(BigInteger balance, Label balanceLabel)
{
if (balance != null)
balanceLabel.setText(Utils.bitcoinValueToFriendlyString(balance));
balanceLabel.setText(BtcFormatter.btcToString(balance));
}
private void updateConfidence(TransactionConfidence confidence, ConfidenceProgressIndicator progressIndicator, Tooltip tooltip)

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="600.0" prefWidth="800.0" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
<AnchorPane AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="io.bitsquare.gui.funds.FundsController">
<TabPane fx:id="tabPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
@ -14,7 +14,7 @@
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<TableView fx:id="addressesTable" id="orderbook-table">
<TableView fx:id="addressesTable" id="orderbook-table" VBox.vgrow="ALWAYS">
<columns>
<TableColumn text="Label" fx:id="labelColumn" minWidth="100" sortable="false">
<cellValueFactory>
@ -29,11 +29,10 @@
<TableColumn text="Balance" fx:id="balanceColumn" minWidth="50" sortable="false"/>
<TableColumn text="Copy" fx:id="copyColumn" minWidth="30" sortable="false"/>
<TableColumn text="Status" fx:id="confidenceColumn" minWidth="30" sortable="false"/>
</columns>
</TableView>
<Button fx:id="addNewAddressButton" text="Add new address" onAction="#onAddNewAddress"/>
<Button fx:id="addNewAddressButton" text="Add new address" onAction="#onAddNewTradeAddress"/>
</VBox>
</Tab>

View File

@ -2,11 +2,10 @@ package io.bitsquare.gui.market.createOffer;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback;
import com.google.inject.Inject;
import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.btc.Fees;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
@ -103,7 +102,8 @@ public class CreateOfferController implements Initializable, ChildController
//TODO
amountTextField.setText("" + (int) (new Random().nextDouble() * 100 / 10 + 1));
//amountTextField.setText("" + (int) (new Random().nextDouble() * 100 / 10 + 1));
amountTextField.setText("1");
priceTextField.setText("" + (int) (499 - new Random().nextDouble() * 1000 / 100));
minAmountTextField.setText("0,1");
collateralTextField.setText("10");
@ -117,7 +117,6 @@ public class CreateOfferController implements Initializable, ChildController
updateVolume();
}
});
priceTextField.textProperty().addListener(new ChangeListener<String>()
{
@Override
@ -141,7 +140,7 @@ public class CreateOfferController implements Initializable, ChildController
bankAccountCountyTextField.setText(user.getCurrentBankAccount().getCountry().getName());
acceptedCountriesTextField.setText(BitSquareFormatter.countryLocalesToString(settings.getAcceptedCountries()));
acceptedLanguagesTextField.setText(BitSquareFormatter.languageLocalesToString(settings.getAcceptedLanguageLocales()));
feeLabel.setText(Utils.bitcoinValueToFriendlyString(Fees.OFFER_CREATION_FEE));
feeLabel.setText(BtcFormatter.btcToString(FeePolicy.CREATE_OFFER_FEE));
}

View File

@ -29,7 +29,6 @@
<Label text="Collateral (%):" GridPane.rowIndex="3"/>
<TextField fx:id="collateralTextField" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
<Label id="form-header-text" text="Offer details" GridPane.rowIndex="4">
<GridPane.margin>
<Insets top="10.0"/>
@ -73,7 +72,6 @@
</ConfidenceProgressIndicator>
<Label fx:id="confirmationLabel" text="Checking confirmations..." visible="false" GridPane.columnIndex="3" GridPane.rowIndex="12"/>
<Button fx:id="closeButton" visible="false" defaultButton="true" onAction="#onClose" text="Close" GridPane.columnIndex="1" GridPane.rowIndex="13"/>
</children>

View File

@ -1,6 +1,8 @@
package io.bitsquare.gui.market.orderbook;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.bitcoin.core.Transaction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.inject.Inject;
import io.bitsquare.bank.BankAccountTypeInfo;
import io.bitsquare.btc.BtcFormatter;
@ -109,6 +111,67 @@ public class OrderBookController implements Initializable, ChildController
// Interface implementation: Initializable
///////////////////////////////////////////////////////////////////////////////////////////
private boolean isRegistered()
{
if (user.getAccountID() == null)
{
Dialogs.CommandLink settingsCommandLink = new Dialogs.CommandLink("Open settings", "You need to configure your settings before you can actively trade.");
Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds", "You need to pay the registration fee before you can actively trade. That is needed as prevention against fraud.");
Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration", "When settings are configured and the fee deposit is done your registration transaction will be published to the Bitcoin \nnetwork.");
List<Dialogs.CommandLink> commandLinks = Arrays.asList(settingsCommandLink, depositFeeCommandLink, sendRegistrationCommandLink);
boolean settingsValid = settings.getAcceptedLanguageLocales().size() > 0;
settingsValid &= settings.getAcceptedCountries().size() > 0;
settingsValid &= settings.getAcceptedArbitrators().size() > 0;
settingsValid &= user.getCurrentBankAccount() != null;
boolean registrationFeeDeposited = walletFacade.getRegistrationBalance().compareTo(BigInteger.ZERO) > 0;
int selectedIndex = settingsValid ? (registrationFeeDeposited ? 2 : 1) : 0;
Action registrationMissingAction = Popups.openRegistrationMissingPopup("Registration missing", "Please follow these steps:", "You need to register before you can place an offer.", commandLinks, selectedIndex);
if (registrationMissingAction == settingsCommandLink)
{
MainController.getInstance().navigateToView(NavigationController.SETTINGS);
}
else if (registrationMissingAction == depositFeeCommandLink)
{
MainController.getInstance().navigateToView(NavigationController.FUNDS);
}
else if (registrationMissingAction == sendRegistrationCommandLink)
{
FutureCallback<Transaction> callback = new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.debug("payRegistrationFee onSuccess");
log.info("payRegistrationFee onSuccess txid:" + transaction.getHashAsString());
}
@Override
public void onFailure(Throwable t)
{
log.debug("payRegistrationFee onFailure");
}
};
try
{
walletFacade.payRegistrationFee(user.getStringifiedBankAccounts(), callback);
user.setAccountID(walletFacade.getRegistrationAddressInfo().toString());
user.setMessagePubKeyAsHex(DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey()));
storage.write(user.getClass().getName(), user);
} catch (InsufficientMoneyException e1)
{
Popups.openErrorPopup("Not enough money available", "There is not enough money available. Please pay in first to your wallet.");
}
}
return false;
}
return true;
}
@Override
public void initialize(URL url, ResourceBundle rb)
{
@ -166,46 +229,7 @@ public class OrderBookController implements Initializable, ChildController
});
createOfferButton.setOnAction(e -> {
if (user.getAccountID() == null)
{
Dialogs.CommandLink settingsCommandLink = new Dialogs.CommandLink("Open settings", "You need to configure your settings before you can actively trade.");
Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds", "You need to pay the registration fee before you can actively trade. That is needed as prevention against fraud.");
Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration", "When settings are configured and the fee deposit is done your registration transaction will be published to the Bitcoin \nnetwork.");
List<Dialogs.CommandLink> commandLinks = Arrays.asList(settingsCommandLink, depositFeeCommandLink, sendRegistrationCommandLink);
boolean settingsValid = settings.getAcceptedLanguageLocales().size() > 0;
settingsValid &= settings.getAcceptedCountries().size() > 0;
settingsValid &= settings.getAcceptedArbitrators().size() > 0;
settingsValid &= user.getCurrentBankAccount() != null;
boolean registrationFeeDeposited = walletFacade.getRegistrationBalance().compareTo(BigInteger.ZERO) > 0;
int selectedIndex = settingsValid ? (registrationFeeDeposited ? 2 : 1) : 0;
Action registrationMissingAction = Popups.openRegistrationMissingPopup("Registration missing", "Please follow these steps:", "You need to register before you can place an offer.", commandLinks, selectedIndex);
if (registrationMissingAction == settingsCommandLink)
{
MainController.getInstance().navigateToView(NavigationController.SETTINGS);
}
else if (registrationMissingAction == depositFeeCommandLink)
{
MainController.getInstance().navigateToView(NavigationController.FUNDS);
}
else if (registrationMissingAction == sendRegistrationCommandLink)
{
try
{
walletFacade.publishRegistrationTxWithExtraData(user.getStringifiedBankAccounts());
user.setAccountID(walletFacade.getRegistrationAddressInfo().toString());
user.setMessagePubKeyAsHex(DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey()));
storage.write(user.getClass().getName(), user);
} catch (InsufficientMoneyException e1)
{
Popups.openErrorPopup("Not enough money available", "There is not enough money available. Please pay in first to your wallet.");
}
}
}
else
if (isRegistered())
{
ChildController nextController = navigationController.navigateToView(NavigationController.CREATE_OFFER, "Create offer");
((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter);
@ -262,14 +286,17 @@ public class OrderBookController implements Initializable, ChildController
private void takeOffer(Offer offer)
{
String title = offer.getDirection() == Direction.BUY ? "Trade: Sell Bitcoin" : "Trade: Buy Bitcoin";
TakerTradeController takerTradeController = (TakerTradeController) navigationController.navigateToView(NavigationController.TAKER_TRADE, title);
if (isRegistered())
{
String title = offer.getDirection() == Direction.BUY ? "Trade: Sell Bitcoin" : "Trade: Buy Bitcoin";
TakerTradeController takerTradeController = (TakerTradeController) navigationController.navigateToView(NavigationController.TAKER_TRADE, title);
BigInteger requestedAmount = offer.getAmount();
if (!amount.getText().equals(""))
requestedAmount = BtcFormatter.stringValueToSatoshis(amount.getText());
BigInteger requestedAmount = offer.getAmount();
if (!amount.getText().equals(""))
requestedAmount = BtcFormatter.stringValueToSatoshis(amount.getText());
takerTradeController.initWithData(offer, requestedAmount);
takerTradeController.initWithData(offer, requestedAmount);
}
}
private void removeOffer(Offer offer)

View File

@ -1,12 +1,8 @@
package io.bitsquare.gui.market.trade;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import com.google.inject.Inject;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.btc.Fees;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.*;
import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
@ -160,7 +156,7 @@ public class TakerTradeController implements Initializable, ChildController
amountTextField.textProperty().addListener(e -> {
applyVolume();
applyCollateral();
totalToPayLabel.setText(getTotalToPay());
totalToPayLabel.setText(getTotalToPayAsString());
});
Label amountRangeLabel = new Label("(" + BtcFormatter.formatSatoshis(offer.getMinAmount(), false) + " - " + BtcFormatter.formatSatoshis(offer.getAmount(), false) + ")");
@ -170,8 +166,8 @@ public class TakerTradeController implements Initializable, ChildController
totalLabel = FormBuilder.addTextField(gridPane, "Total (" + offer.getCurrency() + "):", BitSquareFormatter.formatVolume(getVolume()), ++row);
collateralTextField = FormBuilder.addTextField(gridPane, "Collateral (BTC):", "", ++row);
applyCollateral();
FormBuilder.addTextField(gridPane, "Offer fee (BTC):", Utils.bitcoinValueToFriendlyString(Fees.OFFER_TAKER_FEE.add(Fees.TX_FEE)), ++row);
totalToPayLabel = FormBuilder.addTextField(gridPane, "Total to pay (BTC):", getTotalToPay(), ++row);
FormBuilder.addTextField(gridPane, "Offer fee (BTC):", BtcFormatter.btcToString(FeePolicy.TAKE_OFFER_FEE.add(FeePolicy.TX_FEE)), ++row);
totalToPayLabel = FormBuilder.addTextField(gridPane, "Total to pay (BTC):", getTotalToPayAsString(), ++row);
isOnlineTextField = FormBuilder.addTextField(gridPane, "Online status:", "Checking offerers online status...", ++row);
ConfidenceProgressIndicator isOnlineChecker = new ConfidenceProgressIndicator();
@ -223,6 +219,19 @@ public class TakerTradeController implements Initializable, ChildController
return;
}
// offerId = tradeId
// we don't want to create the trade before the balance check
AddressInfo addressInfo = walletFacade.getAddressInfoByTradeID(offer.getId());
log.debug("balance " + walletFacade.getBalanceForAddress(addressInfo.getAddress()).toString());
if (getTotalToPay().compareTo(walletFacade.getBalanceForAddress(addressInfo.getAddress())) > 0)
{
Popups.openErrorPopup("Insufficient money", "You don't have enough funds for that trade.");
return;
}
trade = trading.createTrade(offer);
trade.setTradeAmount(BtcFormatter.stringValueToSatoshis(amountTextField.getText()));
/* if (!blockChainFacade.verifyAccountRegistration(offer.getAccountID()))
{
Popups.openErrorPopup("Offerers account ID not valid", "Offerers registration tx is not found in blockchain or does not match the requirements.");
@ -259,9 +268,6 @@ public class TakerTradeController implements Initializable, ChildController
progressIndicatorHolder.getChildren().addAll(progressIndicator);
gridPane.add(progressIndicatorHolder, 1, row);
trade = trading.createTrade(offer);
trade.setTradeAmount(BtcFormatter.stringValueToSatoshis(amountTextField.getText()));
takerPaymentProtocol = trading.addTakerPaymentProtocol(trade, new TakerPaymentProtocolListener()
{
@Override
@ -352,7 +358,7 @@ public class TakerTradeController implements Initializable, ChildController
private void releaseBTC(TradeMessage tradeMessage)
{
processStepBar.next();
trading.releaseBTC(trade.getUid(), tradeMessage);
trading.releaseBTC(trade.getId(), tradeMessage);
nextButton.setText("Close");
nextButton.setOnAction(e -> close());
@ -363,12 +369,12 @@ public class TakerTradeController implements Initializable, ChildController
String fiatReceived = BitSquareFormatter.formatVolume(trade.getOffer().getPrice() * BtcFormatter.satoshiToBTC(trade.getTradeAmount()));
FormBuilder.addTextField(gridPane, "You have sold (BTC):", Utils.bitcoinValueToFriendlyString(trade.getTradeAmount()), ++row);
FormBuilder.addTextField(gridPane, "You have sold (BTC):", BtcFormatter.btcToString(trade.getTradeAmount()), ++row);
if (takerIsSelling())
{
FormBuilder.addTextField(gridPane, "You have received (" + offer.getCurrency() + "):\"", fiatReceived, ++row);
FormBuilder.addTextField(gridPane, "Total fees (take offer fee + tx fee):", Utils.bitcoinValueToFriendlyString(Fees.OFFER_TAKER_FEE.add(Fees.TX_FEE)), ++row);
FormBuilder.addTextField(gridPane, "Refunded collateral:", Utils.bitcoinValueToFriendlyString(trade.getCollateralAmount()), ++row);
FormBuilder.addTextField(gridPane, "Total fees (take offer fee + tx fee):", BtcFormatter.btcToString(FeePolicy.TAKE_OFFER_FEE.add(FeePolicy.TX_FEE)), ++row);
FormBuilder.addTextField(gridPane, "Refunded collateral:", BtcFormatter.btcToString(trade.getCollateralAmount()), ++row);
}
else
{
@ -433,19 +439,31 @@ public class TakerTradeController implements Initializable, ChildController
return offer.getPrice() * BitSquareConverter.stringToDouble2(amountTextField.getText());
}
private String getTotalToPay()
private String getTotalToPayAsString()
{
if (takerIsSelling())
{
return BtcFormatter.formatSatoshis(getAmountInSatoshis().add(Fees.OFFER_TAKER_FEE).add(Transaction.MIN_NONDUST_OUTPUT).add(Fees.TX_FEE).add(getCollateralInSatoshis()), false);
return BtcFormatter.formatSatoshis(getTotalToPay(), false);
}
else
{
return BtcFormatter.formatSatoshis(Fees.OFFER_TAKER_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(Fees.TX_FEE).add(getCollateralInSatoshis()), false) + "\n" +
return BtcFormatter.formatSatoshis(getTotalToPay(), false) + "\n" +
BitSquareFormatter.formatVolume(getVolume(), offer.getCurrency());
}
}
private BigInteger getTotalToPay()
{
if (takerIsSelling())
{
return getAmountInSatoshis().add(FeePolicy.TAKE_OFFER_FEE).add(Transaction.MIN_NONDUST_OUTPUT).add(FeePolicy.TX_FEE).add(getCollateralInSatoshis());
}
else
{
return FeePolicy.TAKE_OFFER_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(FeePolicy.TX_FEE).add(getCollateralInSatoshis());
}
}
private void applyCollateral()
{
collateralTextField.setText(BtcFormatter.formatSatoshis(getCollateralInSatoshis(), false));

View File

@ -1,6 +1,9 @@
package io.bitsquare.gui.orders;
import com.google.bitcoin.core.*;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.core.WalletEventListener;
import com.google.bitcoin.script.Script;
import com.google.inject.Inject;
import de.jensd.fx.fontawesome.AwesomeDude;
@ -8,7 +11,7 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.bank.BankAccountTypeInfo;
import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.btc.Fees;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
@ -172,7 +175,7 @@ public class OrdersController implements Initializable, ChildController
public void bankTransferInited(ActionEvent actionEvent)
{
trading.onBankTransferInited(currentTrade.getUid());
trading.onBankTransferInited(currentTrade.getId());
bankTransferInitedButton.setDisable(true);
}
@ -311,10 +314,10 @@ public class OrdersController implements Initializable, ChildController
String fiatPayed = BitSquareFormatter.formatVolume(trade.getOffer().getPrice() * BtcFormatter.satoshiToBTC(trade.getTradeAmount()));
bankAccountTypeTextField.setText(Utils.bitcoinValueToFriendlyString(trade.getTradeAmount()));
bankAccountTypeTextField.setText(BtcFormatter.btcToString(trade.getTradeAmount()));
holderNameTextField.setText(fiatPayed);
primaryBankAccountIDTextField.setText(Utils.bitcoinValueToFriendlyString(Fees.OFFER_CREATION_FEE.add(Fees.TX_FEE)));
secondaryBankAccountIDTextField.setText(Utils.bitcoinValueToFriendlyString(trade.getCollateralAmount()));
primaryBankAccountIDTextField.setText(BtcFormatter.btcToString(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE)));
secondaryBankAccountIDTextField.setText(BtcFormatter.btcToString(trade.getCollateralAmount()));
holderNameCopyIcon.setVisible(false);
primaryBankAccountIDCopyIcon.setVisible(false);

View File

@ -135,47 +135,52 @@ public class SettingsController implements Initializable, ChildController, Navig
public void initialize(URL url, ResourceBundle rb)
{
setupGeneralSettingsScreen();
initBankAccountScreen();
addMockArbitrator();
}
private void addMockArbitrator()
{
String pubKeyAsHex = Utils.bytesToHexString(new ECKey().getPubKey());
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey());
List<Locale> languages = new ArrayList<>();
languages.add(LanguageUtil.getDefaultLanguageLocale());
List<Arbitrator.METHODS> arbitrationMethods = new ArrayList<>();
arbitrationMethods.add(Arbitrator.METHODS.TLS_NOTARY);
List<Arbitrator.ID_VERIFICATIONS> idVerifications = new ArrayList<>();
idVerifications.add(Arbitrator.ID_VERIFICATIONS.PASSPORT);
idVerifications.add(Arbitrator.ID_VERIFICATIONS.GOV_ID);
Arbitrator arbitrator = new Arbitrator(pubKeyAsHex,
messagePubKeyAsHex,
"Manfred Karrer",
Arbitrator.ID_TYPE.REAL_LIFE_ID,
languages,
new Reputation(),
1,
0.01,
0.001,
10,
0.1,
arbitrationMethods,
idVerifications,
"http://bitsquare.io/",
"Bla bla..."
);
try
if (settings.getAcceptedArbitrators() == null || settings.getAcceptedArbitrators().size() == 0)
{
messageFacade.addArbitrator(arbitrator);
} catch (IOException e)
{
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
String pubKeyAsHex = Utils.bytesToHexString(new ECKey().getPubKey());
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(messageFacade.getPubKey());
List<Locale> languages = new ArrayList<>();
languages.add(LanguageUtil.getDefaultLanguageLocale());
List<Arbitrator.METHODS> arbitrationMethods = new ArrayList<>();
arbitrationMethods.add(Arbitrator.METHODS.TLS_NOTARY);
List<Arbitrator.ID_VERIFICATIONS> idVerifications = new ArrayList<>();
idVerifications.add(Arbitrator.ID_VERIFICATIONS.PASSPORT);
idVerifications.add(Arbitrator.ID_VERIFICATIONS.GOV_ID);
Arbitrator arbitrator = new Arbitrator(pubKeyAsHex,
messagePubKeyAsHex,
"Manfred Karrer",
Arbitrator.ID_TYPE.REAL_LIFE_ID,
languages,
new Reputation(),
1,
0.01,
0.001,
10,
0.1,
arbitrationMethods,
idVerifications,
"http://bitsquare.io/",
"Bla bla..."
);
arbitratorList.add(arbitrator);
settings.addAcceptedArbitrator(arbitrator);
storage.write(settings.getClass().getName(), settings);
try
{
messageFacade.addArbitrator(arbitrator);
} catch (IOException e)
{
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
@ -651,6 +656,18 @@ public class SettingsController implements Initializable, ChildController, Navig
{
resetBankAccountInput();
}
//TODO
bankAccountTypesComboBox.getSelectionModel().selectFirst();
bankAccountCurrencyComboBox.getSelectionModel().selectFirst();
bankAccountRegionComboBox.getSelectionModel().select(3);
bankAccountCountryComboBox.getSelectionModel().select(5);
bankAccountTitleTextField.setText("dummy");
bankAccountHolderNameTextField.setText("dummy");
bankAccountPrimaryIDTextField.setText("dummy");
bankAccountSecondaryIDTextField.setText("dummy");
if (user.getCurrentBankAccount() == null)
onSaveBankAccount(null);
}
private void resetBankAccountInput()
@ -798,7 +815,6 @@ public class SettingsController implements Initializable, ChildController, Navig
bankAccountCountryComboBox.setVisible(true);
int countryIndex = bankAccountCountryComboBox.getItems().indexOf(currentCountry);
bankAccountCountryComboBox.getSelectionModel().select(countryIndex);
}
}

View File

@ -2,6 +2,7 @@ package io.bitsquare.gui.util;
import com.google.bitcoin.core.*;
import com.google.bitcoin.script.Script;
import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
@ -205,7 +206,7 @@ public class ConfidenceDisplay
}
if (balanceTextField != null)
balanceTextField.setText(Utils.bitcoinValueToFriendlyString(balance));
balanceTextField.setText(BtcFormatter.btcToString(balance));
}
private void updateConfidence(Transaction tx)

View File

@ -48,10 +48,7 @@ public class CountryUtil
@Override
public boolean apply(@Nullable Country country)
{
if (selectedRegion != null && country != null)
return country.getRegion().equals(selectedRegion);
else
return false;
return selectedRegion != null && country != null && country.getRegion().equals(selectedRegion);
}
}));

View File

@ -211,7 +211,7 @@ public class MessageFacade
public void addOffer(Offer offer) throws IOException
{
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
final Number160 contentKey = Number160.createHash(offer.getUID());
final Number160 contentKey = Number160.createHash(offer.getId());
final Data offerData = new Data(offer);
//offerData.setTTLSeconds(5);
final FutureDHT addFuture = myPeer.put(locationKey).setData(contentKey, offerData).start();
@ -267,7 +267,7 @@ public class MessageFacade
public void removeOffer(Offer offer) throws IOException
{
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
Number160 contentKey = Number160.createHash(offer.getUID());
Number160 contentKey = Number160.createHash(offer.getId());
log.debug("removeOffer");
FutureDHT removeFuture = myPeer.remove(locationKey).setReturnResults().setContentKey(contentKey).start();
removeFuture.addListener(new BaseFutureAdapter<BaseFuture>()

View File

@ -11,6 +11,7 @@ public class TradeMessage implements Serializable
{
private static final long serialVersionUID = 7916445031849763995L;
private String uid;
private String takerMessagePubKey;
@ -37,7 +38,8 @@ public class TradeMessage implements Serializable
private String accountID;
private String offererPubKey;
private String preparedOffererDepositTxAsHex;
private long offererTxOutIndex;
private long takerTxOutIndex;
private String payoutTxAsHex;
public TradeMessage(TradeMessageType type, String offerUID)
@ -60,7 +62,7 @@ public class TradeMessage implements Serializable
uid = UUID.randomUUID().toString();
}
public TradeMessage(TradeMessageType type, String offerUID, BankAccount bankAccount, String accountID, String offererPubKey, String preparedOffererDepositTxAsHex)
public TradeMessage(TradeMessageType type, String offerUID, BankAccount bankAccount, String accountID, String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex)
{
this.offerUID = offerUID;
this.type = type;
@ -68,6 +70,7 @@ public class TradeMessage implements Serializable
this.accountID = accountID;
this.offererPubKey = offererPubKey;
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
this.offererTxOutIndex = offererTxOutIndex;
uid = UUID.randomUUID().toString();
}
@ -81,7 +84,9 @@ public class TradeMessage implements Serializable
String txConnOutAsHex,
String contractAsJson,
String takerContractSignature,
String takerPayoutAddress)
String takerPayoutAddress,
long takerTxOutIndex,
long offererTxOutIndex)
{
this.offerUID = offerUID;
this.type = type;
@ -94,6 +99,8 @@ public class TradeMessage implements Serializable
this.contractAsJson = contractAsJson;
this.takerContractSignature = takerContractSignature;
this.takerPayoutAddress = takerPayoutAddress;
this.takerTxOutIndex = takerTxOutIndex;
this.offererTxOutIndex = offererTxOutIndex;
uid = UUID.randomUUID().toString();
}
@ -260,4 +267,13 @@ public class TradeMessage implements Serializable
return payoutTxAsHex;
}
public long getOffererTxOutIndex()
{
return offererTxOutIndex;
}
public long getTakerTxOutIndex()
{
return takerTxOutIndex;
}
}

View File

@ -20,7 +20,7 @@ public class Offer implements Serializable
private Direction direction;
private Currency currency;
private String uid;
private String id;
private double price;
private BigInteger amount;
@ -69,7 +69,7 @@ public class Offer implements Serializable
this.acceptedCountries = acceptedCountries;
this.acceptedLanguageLocales = acceptedLanguageLocales;
this.uid = UUID.randomUUID().toString();
this.id = UUID.randomUUID().toString();
}
@ -92,9 +92,9 @@ public class Offer implements Serializable
return messagePubKeyAsHex;
}
public String getUID()
public String getId()
{
return uid;
return id;
}
public double getPrice()
@ -178,7 +178,7 @@ public class Offer implements Serializable
return "Offer{" +
"direction=" + direction +
", currency=" + currency +
", uid='" + uid + '\'' +
", uid='" + id + '\'' +
", price=" + price +
", amount=" + amount +
", minAmount=" + minAmount +

View File

@ -93,9 +93,9 @@ public class Trade implements Serializable
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public String getUid()
public String getId()
{
return offer.getUID();
return offer.getId();
}
public Offer getOffer()

View File

@ -7,7 +7,6 @@ import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback;
import com.google.inject.Inject;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.Fees;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
@ -99,39 +98,37 @@ public class Trading
public void placeNewOffer(Offer offer, FutureCallback<Transaction> callback) throws InsufficientMoneyException
{
if (myOffers.containsKey(offer.getUID()))
throw new IllegalStateException("offers contains already a offer with the ID " + offer.getUID());
if (myOffers.containsKey(offer.getId()))
throw new IllegalStateException("offers contains already a offer with the ID " + offer.getId());
myOffers.put(offer.getUID(), offer);
//TODO for testing
//storage.write(storageKey + ".offers", myOffers);
walletFacade.payOfferFee(Fees.OFFER_CREATION_FEE, callback);
myOffers.put(offer.getId(), offer);
walletFacade.payCreateOfferFee(callback);
}
public void removeOffer(Offer offer) throws IOException
{
myOffers.remove(offer.getUID());
myOffers.remove(offer.getId());
storage.write(storageKey + ".offers", myOffers);
}
public Trade createTrade(Offer offer)
{
if (trades.containsKey(offer.getUID()))
throw new IllegalStateException("trades contains already a trade with the ID " + offer.getUID());
if (trades.containsKey(offer.getId()))
throw new IllegalStateException("trades contains already a trade with the ID " + offer.getId());
Trade trade = new Trade(offer);
trades.put(offer.getUID(), trade);
trades.put(offer.getId(), trade);
//TODO for testing
//storage.write(storageKey + ".trades", trades);
this.newTradeProperty.set(trade.getUid());
this.newTradeProperty.set(trade.getId());
return trade;
}
public void removeTrade(Trade trade) throws IOException
{
trades.remove(trade.getUid());
trades.remove(trade.getId());
storage.write(storageKey + ".trades", trades);
}
@ -143,14 +140,14 @@ public class Trading
public TakerPaymentProtocol addTakerPaymentProtocol(Trade trade, TakerPaymentProtocolListener listener)
{
TakerPaymentProtocol takerPaymentProtocol = new TakerPaymentProtocol(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
takerPaymentProtocols.put(trade.getUid(), takerPaymentProtocol);
takerPaymentProtocols.put(trade.getId(), takerPaymentProtocol);
return takerPaymentProtocol;
}
public OffererPaymentProtocol addOffererPaymentProtocol(Trade trade, OffererPaymentProtocolListener listener)
{
OffererPaymentProtocol offererPaymentProtocol = new OffererPaymentProtocol(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
offererPaymentProtocols.put(trade.getUid(), offererPaymentProtocol);
offererPaymentProtocols.put(trade.getId(), offererPaymentProtocol);
return offererPaymentProtocol;
}

View File

@ -141,7 +141,7 @@ public class OrderBook implements OrderBookListener
&& priceResult
&& arbitratorResult;
/*
/*
log.debug("result = " + result +
", currencyResult = " + currencyResult +
", countryResult = " + countryResult +
@ -241,7 +241,7 @@ public class OrderBook implements OrderBookListener
@Override
public boolean test(OrderBookListItem orderBookListItem)
{
return orderBookListItem.getOffer().getUID().equals(offer.getUID());
return orderBookListItem.getOffer().getId().equals(offer.getId());
}
});
}

View File

@ -4,6 +4,7 @@ import com.google.bitcoin.core.*;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
@ -140,13 +141,13 @@ public class OffererPaymentProtocol
offererPaymentProtocolListener.onProgress(getProgress());
// 1.3a Send accept take offer message
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.ACCEPT_TAKE_OFFER_REQUEST, trade.getUid());
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.ACCEPT_TAKE_OFFER_REQUEST, trade.getId());
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
}
else
{
log.debug("1.3 offer already requested REJECT_TAKE_OFFER_REQUEST");
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REJECT_TAKE_OFFER_REQUEST, trade.getUid());
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REJECT_TAKE_OFFER_REQUEST, trade.getId());
TradeMessageListener listener = new TradeMessageListener()
{
@Override
@ -215,7 +216,7 @@ public class OffererPaymentProtocol
log.debug("2.5 createDepositTx");
BigInteger offererInputAmount = trade.getCollateralAmount();
String offererPubKey = walletFacade.getPubKeyAsHex();
String offererPubKey = walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
String takerPubKey = requestTradeMessage.getTakerMultiSigPubKey();
String arbitratorPubKey = offer.getArbitrator().getPubKeyAsHex();
@ -225,17 +226,18 @@ public class OffererPaymentProtocol
checkNotNull(arbitratorPubKey);
log.debug("2.5 offererCreatesMSTxAndAddPayment");
log.debug("offererInputAmount " + Utils.bitcoinValueToFriendlyString(offererInputAmount));
log.debug("offererInputAmount " + BtcFormatter.btcToString(offererInputAmount));
log.debug("offerer pubkey " + offererPubKey);
log.debug("taker pubkey " + takerPubKey);
log.debug("arbitrator pubkey " + arbitratorPubKey);
try
{
Transaction tx = walletFacade.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerPubKey, arbitratorPubKey);
Transaction tx = walletFacade.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerPubKey, arbitratorPubKey, trade.getId());
preparedOffererDepositTxAsHex = Utils.bytesToHexString(tx.bitcoinSerialize());
long offererTxOutIndex = tx.getInput(0).getOutpoint().getIndex();
log.debug("2.5 deposit tx created: " + tx);
log.debug("2.5 deposit txAsHex: " + preparedOffererDepositTxAsHex);
sendDepositTxAndDataForContract(preparedOffererDepositTxAsHex, offererPubKey);
sendDepositTxAndDataForContract(preparedOffererDepositTxAsHex, offererPubKey, offererTxOutIndex);
} catch (InsufficientMoneyException e)
{
log.warn("2.5 InsufficientMoneyException " + e.getMessage());
@ -250,7 +252,7 @@ public class OffererPaymentProtocol
// Step 2.6
///////////////////////////////////////////////////////////////////////////////////////////
private void sendDepositTxAndDataForContract(String preparedOffererDepositTxAsHex, String offererPubKey)
private void sendDepositTxAndDataForContract(String preparedOffererDepositTxAsHex, String offererPubKey, long offererTxOutIndex)
{
log.debug("2.6 sendDepositTxAndDataForContract");
// Send all the requested data
@ -280,12 +282,12 @@ public class OffererPaymentProtocol
BankAccount bankAccount = user.getBankAccount(offer.getBankAccountUID());
String accountID = user.getAccountID();
checkNotNull(trade.getUid());
checkNotNull(trade.getId());
checkNotNull(bankAccount);
checkNotNull(accountID);
checkNotNull(preparedOffererDepositTxAsHex);
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_TAKER_DEPOSIT_PAYMENT, trade.getUid(), bankAccount, accountID, offererPubKey, preparedOffererDepositTxAsHex);
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_TAKER_DEPOSIT_PAYMENT, trade.getId(), bankAccount, accountID, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
log.debug("2.6 sendTradingMessage");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
}
@ -352,13 +354,13 @@ public class OffererPaymentProtocol
log.debug("3.3 offerer contract created: " + contract.toString());
String contractAsJson = Utilities.objectToJson(contract);
log.debug("3.3 contractAsJson: " + contractAsJson);
// log.debug("3.3 contractAsJson: " + contractAsJson);
log.debug("3.3 requestTradingMessage.getContractAsJson(): " + requestTradeMessage.getContractAsJson());
if (contractAsJson.equals(requestTradeMessage.getContractAsJson()))
{
log.debug("3.3 The 2 contracts as json does match");
String signature = cryptoFacade.signContract(walletFacade.getRegistrationKey(), contractAsJson);
String signature = cryptoFacade.signContract(walletFacade.getRegistrationAddressInfo().getKey(), contractAsJson);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature);
@ -407,7 +409,8 @@ public class OffererPaymentProtocol
try
{
log.debug("3.4 offererSignAndSendTx");
depositTransaction = walletFacade.offererSignAndPublishTx(preparedOffererDepositTxAsHex, signedTakerDepositTxAsHex, txConnOutAsHex, txScriptSigAsHex, callback);
depositTransaction = walletFacade.offererSignAndPublishTx(preparedOffererDepositTxAsHex, signedTakerDepositTxAsHex, txConnOutAsHex, txScriptSigAsHex,
requestTradeMessage.getOffererTxOutIndex(), requestTradeMessage.getTakerTxOutIndex(), callback);
} catch (Exception e)
{
log.error("3.4 error at walletFacade.offererSignAndSendTx: " + e.getMessage());
@ -440,7 +443,7 @@ public class OffererPaymentProtocol
offererPaymentProtocolListener.onFailure("sendDepositTxAndDataForContract onSendTradingMessageFailed");
}
};
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.DEPOSIT_TX_PUBLISHED, trade.getUid(), Utils.bytesToHexString(transaction.bitcoinSerialize()));
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.DEPOSIT_TX_PUBLISHED, trade.getId(), Utils.bytesToHexString(transaction.bitcoinSerialize()));
log.debug("3.5 sendTradingMessage");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
@ -476,10 +479,10 @@ public class OffererPaymentProtocol
updateConfirmation(tx.getConfidence());
//todo just for testing now, dont like to wait so long...
/* if (tx.getConfidence().numBroadcastPeers() > 3)
/* if (tx.getConfidenceForAddress().numBroadcastPeers() > 3)
{
onDepositTxConfirmedInBlockchain();
transaction.getConfidence().removeEventListener(this);
transaction.getConfidenceForAddress().removeEventListener(this);
} */
}
@ -555,14 +558,14 @@ public class OffererPaymentProtocol
log.debug("depositTransaction.getHashAsString() " + depositTransaction.getHashAsString());
log.debug("takerPayoutAddress " + takerPayoutAddress);
log.debug("walletFacade.offererCreatesAndSignsPayoutTx");
Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransaction.getHashAsString(), offererPaybackAmount, takerPaybackAmount, takerPayoutAddress);
Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransaction.getHashAsString(), offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, trade.getId());
ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString();
String offererSignatureS = offererSignature.s.toString();
String depositTxAsHex = result.getValue();
String offererPayoutAddress = walletFacade.getTradingAddress();
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.BANK_TX_INITED, trade.getUid(),
String offererPayoutAddress = walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString();
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.BANK_TX_INITED, trade.getId(),
depositTxAsHex,
offererSignatureR,
offererSignatureS,

View File

@ -7,7 +7,7 @@ import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.Fees;
import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade;
@ -152,7 +152,7 @@ public class TakerPaymentProtocol
takerPaymentProtocolListener.onProgress(getProgress());
// Send the take offer request
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_TAKE_OFFER, trade.getUid());
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_TAKE_OFFER, trade.getId());
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
}
@ -190,13 +190,13 @@ public class TakerPaymentProtocol
private void payOfferFee(Trade trade)
{
log.debug("2.1 payOfferFee");
log.debug("2.1 payTakeOfferFee");
FutureCallback<Transaction> callback = new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction transaction)
{
log.debug("2.1 payOfferFee onSuccess");
log.debug("2.1 payTakeOfferFee onSuccess");
log.info("sendResult onSuccess txid:" + transaction.getHashAsString());
// Offer fee payed successfully.
@ -211,15 +211,15 @@ public class TakerPaymentProtocol
@Override
public void onFailure(Throwable t)
{
log.debug("2.1 payOfferFee onFailure");
takerPaymentProtocolListener.onFailure("payOfferFee onFailure " + t.getMessage());
log.debug("2.1 payTakeOfferFee onFailure");
takerPaymentProtocolListener.onFailure("payTakeOfferFee onFailure " + t.getMessage());
}
};
try
{
// Pay the offer fee
takerPaymentProtocolListener.onProgress(getProgress());
walletFacade.payOfferFee(Fees.OFFER_TAKER_FEE, callback);
walletFacade.payTakeOfferFee(callback);
} catch (InsufficientMoneyException e)
{
takerPaymentProtocolListener.onProgress(getProgress());
@ -263,10 +263,10 @@ public class TakerPaymentProtocol
// 2.3. send request for the account details and send fee tx id so offerer can verify that the fee has been paid.
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.TAKE_OFFER_FEE_PAYED,
trade.getUid(),
trade.getId(),
trade.getTradeAmount(),
takeOfferFeeTxID,
walletFacade.getPubKeyAsHex());
walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString());
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
}
@ -343,7 +343,7 @@ public class TakerPaymentProtocol
log.debug("2.9 contract created: " + contract.toString());
String contractAsJson = Utilities.objectToJson(contract);
String signature = cryptoFacade.signContract(walletFacade.getRegistrationKey(), contractAsJson);
String signature = cryptoFacade.signContract(walletFacade.getRegistrationAddressInfo().getKey(), contractAsJson);
//log.debug("2.9 contractAsJson: " + contractAsJson);
log.debug("2.9 contract signature: " + signature);
@ -369,7 +369,7 @@ public class TakerPaymentProtocol
BigInteger msOutputAmount = trade.getTradeAmount().add(collateralAmount).add(collateralAmount);
String offererPubKey = requestTradeMessage.getOffererPubKey();
String takerPubKey = walletFacade.getPubKeyAsHex();
String takerPubKey = walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
String arbitratorPubKey = offer.getArbitrator().getPubKeyAsHex();
String preparedOffererDepositTxAsHex = requestTradeMessage.getPreparedOffererDepositTxAsHex();
@ -381,17 +381,18 @@ public class TakerPaymentProtocol
checkNotNull(preparedOffererDepositTxAsHex);
log.debug("2.10 offererCreatesMSTxAndAddPayment");
log.debug("takerAmount " + Utils.bitcoinValueToFriendlyString(takerInputAmount));
log.debug("msOutputAmount " + Utils.bitcoinValueToFriendlyString(msOutputAmount));
log.debug("takerAmount " + BtcFormatter.btcToString(takerInputAmount));
log.debug("msOutputAmount " + BtcFormatter.btcToString(msOutputAmount));
log.debug("offerer pubkey " + offererPubKey);
log.debug("taker pubkey " + takerPubKey);
log.debug("arbitrator pubkey " + arbitratorPubKey);
log.debug("preparedOffererDepositTxAsHex " + preparedOffererDepositTxAsHex);
try
{
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(takerInputAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, preparedOffererDepositTxAsHex);
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(takerInputAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, preparedOffererDepositTxAsHex, trade.getId());
log.debug("2.10 deposit tx created: " + signedTakerDepositTx);
sendSignedTakerDepositTxAsHex(signedTakerDepositTx);
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
sendSignedTakerDepositTxAsHex(signedTakerDepositTx, takerTxOutIndex, requestTradeMessage.getOffererTxOutIndex());
} catch (InterruptedException | AddressFormatException | ExecutionException | InsufficientMoneyException e)
{
log.error("2.10 error at walletFacade.takerAddPaymentAndSign: " + e.getMessage());
@ -403,7 +404,7 @@ public class TakerPaymentProtocol
// Step 2.11 Send the tx to the offerer
///////////////////////////////////////////////////////////////////////////////////////////
private void sendSignedTakerDepositTxAsHex(Transaction signedTakerDepositTx)
private void sendSignedTakerDepositTxAsHex(Transaction signedTakerDepositTx, long takerTxOutIndex, long offererTxOutIndex)
{
log.debug("2.11 sendSignedTakerDepositTxAsHex");
@ -437,14 +438,14 @@ public class TakerPaymentProtocol
String txScriptSigAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes());
String txConnOutAsHex = com.google.bitcoin.core.Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize());
//TODO just 1 address supported yet
String payoutAddress = walletFacade.getTradingAddress();
String payoutAddress = walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString();
log.debug("2.10 deposit txAsHex: " + signedTakerDepositTxAsHex);
log.debug("2.10 txScriptSigAsHex: " + txScriptSigAsHex);
log.debug("2.10 txConnOutAsHex: " + txConnOutAsHex);
log.debug("2.10 payoutAddress: " + payoutAddress);
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.REQUEST_OFFERER_DEPOSIT_PUBLICATION,
trade.getUid(),
trade.getId(),
bankAccount,
accountID,
messagePubKey,
@ -453,7 +454,10 @@ public class TakerPaymentProtocol
txConnOutAsHex,
contractAsJson,
signature,
payoutAddress);
payoutAddress,
takerTxOutIndex,
offererTxOutIndex
);
log.debug("2.11 sendTradingMessage");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);
@ -542,6 +546,7 @@ public class TakerPaymentProtocol
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress,
trade.getId(),
callback);
} catch (InsufficientMoneyException e)
{
@ -577,7 +582,7 @@ public class TakerPaymentProtocol
}
};
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.PAYOUT_TX_PUBLISHED, trade.getUid());
TradeMessage tradeMessage = new TradeMessage(TradeMessageType.PAYOUT_TX_PUBLISHED, trade.getId());
tradeMessage.setPayoutTxAsHex(payoutTxAsHex);
log.debug("3.13 sendTradeMessage PAYOUT_TX_PUBLISHED");
messageFacade.sendTradeMessage(peerAddress, tradeMessage, listener);

View File

@ -93,7 +93,8 @@ public class Arbitrator implements Serializable
this.webUrl = webUrl;
this.description = description;
UID = pubKeyAsHex;
//TODO for mock arbitrator
UID = name;
}