Second trade process basically working (WIP)

This commit is contained in:
Manfred Karrer 2015-04-01 23:07:47 +02:00
parent 37a358b716
commit 21fb0920c8
70 changed files with 1071 additions and 583 deletions

View File

@ -61,23 +61,23 @@ import static com.google.inject.internal.util.$Preconditions.*;
Deposit tx:
To keep the multiple partial deposit tx consistent with the final deposit tx used for publishing
we use always use offerers in/outputs first then takers in/outputs.
we use always use buyers in/outputs first then sellers in/outputs.
IN[0] offerer (mandatory) e.g. 0.1 BTC
IN[...] optional additional offerer inputs (normally never used as we pay from trade fee tx and always have 1 output there)
IN[...] taker (mandatory) e.g. 1.1001 BTC
IN[...] optional additional taker inputs (normally never used as we pay from trade fee tx and always have 1 output there)
IN[0] buyer (mandatory) e.g. 0.1 BTC
IN[...] optional additional buyer inputs (normally never used as we pay from trade fee tx and always have 1 output there)
IN[...] seller (mandatory) e.g. 1.1001 BTC
IN[...] optional additional seller inputs (normally never used as we pay from trade fee tx and always have 1 output there)
OUT[0] Multisig output (include tx fee for payout tx) e.g. 1.2001
OUT[1] offerer change (normally never used as we pay from trade fee tx and always have 1 output there)
OUT[...] optional additional offerer outputs (supported but no use case yet for that)
OUT[...] taker change (normally never used as we pay from trade fee tx and always have 1 output there)
OUT[...] optional additional taker outputs (supported but no use case yet for that)
OUT[1] buyer change (normally never used as we pay from trade fee tx and always have 1 output there)
OUT[...] optional additional buyer outputs (supported but no use case yet for that)
OUT[...] seller change (normally never used as we pay from trade fee tx and always have 1 output there)
OUT[...] optional additional seller outputs (supported but no use case yet for that)
FEE tx fee 0.0001 BTC
Payout tx:
IN[0] Multisig output form deposit Tx (signed by offerer and trader)
OUT[0] Offerer payout address
OUT[1] Taker payout address
IN[0] Multisig output form deposit Tx (signed by buyer and trader)
OUT[0] Buyer payout address
OUT[1] Seller payout address
*/
public class TradeWalletService {
@ -103,7 +103,7 @@ public class TradeWalletService {
// Trade fee
///////////////////////////////////////////////////////////////////////////////////////////
public Transaction createOfferFeeTx(AddressEntry offererAddressEntry) throws InsufficientMoneyException {
public Transaction createOfferFeeTx(AddressEntry buyerAddressEntry) throws InsufficientMoneyException {
Transaction createOfferFeeTx = new Transaction(params);
Coin fee = FeePolicy.CREATE_OFFER_FEE.subtract(FeePolicy.TX_FEE);
createOfferFeeTx.addOutput(fee, feePolicy.getAddressForCreateOfferFee());
@ -111,8 +111,8 @@ public class TradeWalletService {
sendRequest.shuffleOutputs = false;
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to
// wait for 1 confirmation)
sendRequest.coinSelector = new AddressBasedCoinSelector(params, offererAddressEntry, true);
sendRequest.changeAddress = offererAddressEntry.getAddress();
sendRequest.coinSelector = new AddressBasedCoinSelector(params, buyerAddressEntry, true);
sendRequest.changeAddress = buyerAddressEntry.getAddress();
wallet.completeTx(sendRequest);
printTxWithInputs("createOfferFeeTx", createOfferFeeTx);
return createOfferFeeTx;
@ -123,7 +123,7 @@ public class TradeWalletService {
Futures.addCallback(future, callback);
}
public Transaction createTakeOfferFeeTx(AddressEntry takerAddressEntry) throws InsufficientMoneyException {
public Transaction createTakeOfferFeeTx(AddressEntry sellerAddressEntry) throws InsufficientMoneyException {
Transaction takeOfferFeeTx = new Transaction(params);
Coin fee = FeePolicy.TAKE_OFFER_FEE.subtract(FeePolicy.TX_FEE);
takeOfferFeeTx.addOutput(fee, feePolicy.getAddressForTakeOfferFee());
@ -132,8 +132,8 @@ public class TradeWalletService {
sendRequest.shuffleOutputs = false;
// we allow spending of unconfirmed takeOfferFeeTx (double spend risk is low and usability would suffer if we need to
// wait for 1 confirmation)
sendRequest.coinSelector = new AddressBasedCoinSelector(params, takerAddressEntry, true);
sendRequest.changeAddress = takerAddressEntry.getAddress();
sendRequest.coinSelector = new AddressBasedCoinSelector(params, sellerAddressEntry, true);
sendRequest.changeAddress = sellerAddressEntry.getAddress();
wallet.completeTx(sendRequest);
printTxWithInputs("takeOfferFeeTx", takeOfferFeeTx);
return takeOfferFeeTx;
@ -162,22 +162,22 @@ public class TradeWalletService {
}
public Result createOffererDepositTxInputs(Coin offererInputAmount, AddressEntry offererAddressEntry) throws
public Result createDepositTxInputs(Coin buyerInputAmount, AddressEntry buyerAddressEntry) throws
TransactionVerificationException, WalletException {
log.trace("createOffererDepositTxInputs called");
log.trace("offererInputAmount " + offererInputAmount.toFriendlyString());
log.trace("offererAddressEntry " + offererAddressEntry.toString());
log.trace("createDepositTxInputs called");
log.trace("buyerInputAmount " + buyerInputAmount.toFriendlyString());
log.trace("buyerAddressEntry " + buyerAddressEntry.toString());
Coin balance = getBalance(wallet.calculateAllSpendCandidates(true), offererAddressEntry.getAddress());
Coin balance = getBalance(wallet.calculateAllSpendCandidates(true), buyerAddressEntry.getAddress());
log.trace("balance " + balance.toFriendlyString());
// We pay the tx fee 2 times to the deposit tx:
// 1. Will be spent when publishing the deposit tx (paid by offerer)
// 1. Will be spent when publishing the deposit tx (paid by buyer)
// 2. Will be added to the MS amount, so when publishing the payout tx the fee is already there and the outputs are not changed by fee reduction
// The fee for the payout will be paid by the taker.
// The fee for the payout will be paid by the seller.
// offererInputAmount includes the tx fee. So we subtract the fee to get the dummyOutputAmount.
Coin dummyOutputAmount = offererInputAmount.subtract(FeePolicy.TX_FEE);
// buyerInputAmount includes the tx fee. So we subtract the fee to get the dummyOutputAmount.
Coin dummyOutputAmount = buyerInputAmount.subtract(FeePolicy.TX_FEE);
Transaction dummyTX = new Transaction(params);
// The output is just used to get the right inputs and change outputs, so we use an anonymous ECKey, as it will never be used for anything.
@ -188,7 +188,7 @@ public class TradeWalletService {
// Fin the needed inputs to pay the output, optional add change output.
// Normally only 1 input and no change output is used, but we support multiple inputs and outputs. Our spending transaction output is from the create
// offer fee payment. In future changes (in case of no offer fee) multiple inputs might become used.
addAvailableInputsAndChangeOutputs(dummyTX, offererAddressEntry);
addAvailableInputsAndChangeOutputs(dummyTX, buyerAddressEntry);
// The completeTx() call signs the input, but we don't want to pass over signed tx inputs
// But to be safe and to support future changes (in case of no offer fee) we handle potential multiple inputs
@ -198,10 +198,10 @@ public class TradeWalletService {
// The created tx looks like:
/*
IN[0] any input > offererInputAmount (including tx fee) (unsigned)
IN[0] any input > buyerInputAmount (including tx fee) (unsigned)
IN[1...n] optional inputs supported, but currently there is just 1 input (unsigned)
OUT[0] dummyOutputAmount (offererInputAmount - tx fee)
OUT[1] Optional Change = offererInputAmount - dummyOutputAmount - tx fee
OUT[0] dummyOutputAmount (buyerInputAmount - tx fee)
OUT[1] Optional Change = buyerInputAmount - dummyOutputAmount - tx fee
OUT[2...n] optional more outputs are supported, but currently there is just max. 1 optional change output
*/
@ -210,7 +210,7 @@ public class TradeWalletService {
List<TransactionOutput> connectedOutputsForAllInputs = dummyTX.getInputs().stream().map(TransactionInput::getConnectedOutput)
.collect(Collectors.toList());
// Only save offerer outputs, the dummy output (index 1) is ignored
// Only save buyer outputs, the dummy output (index 1) is ignored
List<TransactionOutput> outputs = new ArrayList<>();
for (int i = 1; i < dummyTX.getOutputs().size(); i++) {
outputs.add(dummyTX.getOutputs().get(i));
@ -219,150 +219,148 @@ public class TradeWalletService {
return new Result(connectedOutputsForAllInputs, outputs);
}
public Result takerCreatesAndSignsDepositTx(Coin takerInputAmount,
Coin msOutputAmount,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs,
AddressEntry takerAddressInfo,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey) throws SigningException, TransactionVerificationException, WalletException {
log.trace("takerCreatesAndSignsDepositTx called");
log.trace("takerInputAmount " + takerInputAmount.toFriendlyString());
public Result createAndSignDepositTx(Coin sellerInputAmount,
Coin msOutputAmount,
List<TransactionOutput> buyerConnectedOutputsForAllInputs,
List<TransactionOutput> buyerOutputs,
AddressEntry sellerAddressInfo,
byte[] buyerPubKey,
byte[] sellerPubKey,
byte[] arbitratorPubKey) throws SigningException, TransactionVerificationException, WalletException {
log.trace("createAndSignDepositTx called");
log.trace("sellerInputAmount " + sellerInputAmount.toFriendlyString());
log.trace("msOutputAmount " + msOutputAmount.toFriendlyString());
log.trace("offererConnectedOutputsForAllInputs " + offererConnectedOutputsForAllInputs.toString());
log.trace("offererOutputs " + offererOutputs.toString());
log.trace("takerAddressInfo " + takerAddressInfo.toString());
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("buyerConnectedOutputsForAllInputs " + buyerConnectedOutputsForAllInputs.toString());
log.trace("buyerOutputs " + buyerOutputs.toString());
log.trace("sellerAddressInfo " + sellerAddressInfo.toString());
log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
checkArgument(offererConnectedOutputsForAllInputs.size() > 0);
if (!Utils.HEX.encode(takerAddressInfo.getPubKey()).equals(Utils.HEX.encode(takerPubKey)))
throw new SigningException("TakerPubKey not matching key pair from addressEntry");
checkArgument(buyerConnectedOutputsForAllInputs.size() > 0);
// First we construct a dummy TX to get the inputs and outputs we want to use for the real deposit tx.
Transaction dummyTx = new Transaction(params);
Coin dummyOutputAmount = takerInputAmount.subtract(FeePolicy.TX_FEE);
Coin dummyOutputAmount = sellerInputAmount.subtract(FeePolicy.TX_FEE);
TransactionOutput dummyOutput = new TransactionOutput(params, dummyTx, dummyOutputAmount, new ECKey().toAddress(params));
dummyTx.addOutput(dummyOutput);
addAvailableInputsAndChangeOutputs(dummyTx, takerAddressInfo);
List<TransactionInput> takerInputs = dummyTx.getInputs();
List<TransactionOutput> takerOutputs = new ArrayList<>();
addAvailableInputsAndChangeOutputs(dummyTx, sellerAddressInfo);
List<TransactionInput> sellererInputs = dummyTx.getInputs();
List<TransactionOutput> sellerOutputs = new ArrayList<>();
// we store optional change outputs (ignoring dummyOutput)
for (int i = 1; i < dummyTx.getOutputs().size(); i++) {
takerOutputs.add(dummyTx.getOutput(i));
sellerOutputs.add(dummyTx.getOutput(i));
}
// Now we construct the real deposit tx
Transaction preparedDepositTx = new Transaction(params);
// Add offerer inputs (normally its just 1 input)
for (TransactionOutput connectedOutputForInput : offererConnectedOutputsForAllInputs) {
// Add buyer inputs (normally its just 1 input)
for (TransactionOutput connectedOutputForInput : buyerConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
TransactionInput transactionInput = new TransactionInput(params, preparedDepositTx, new byte[]{}, outPoint, connectedOutputForInput.getValue());
preparedDepositTx.addInput(transactionInput);
}
// Add taker inputs
List<TransactionOutput> takerConnectedOutputsForAllInputs = new ArrayList<>();
for (TransactionInput input : takerInputs) {
// Add seller inputs
List<TransactionOutput> sellerConnectedOutputsForAllInputs = new ArrayList<>();
for (TransactionInput input : sellererInputs) {
preparedDepositTx.addInput(input);
takerConnectedOutputsForAllInputs.add(input.getConnectedOutput());
sellerConnectedOutputsForAllInputs.add(input.getConnectedOutput());
}
// Add MultiSig output
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey);
// Tx fee for deposit tx will be paid by offerer.
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
// Tx fee for deposit tx will be paid by buyer.
TransactionOutput p2SHMultiSigOutput = new TransactionOutput(params, preparedDepositTx, msOutputAmount, p2SHMultiSigOutputScript.getProgram());
preparedDepositTx.addOutput(p2SHMultiSigOutput);
// Add optional offerer outputs
offererOutputs.forEach(preparedDepositTx::addOutput);
// Add optional buyer outputs
buyerOutputs.forEach(preparedDepositTx::addOutput);
Coin takersSpendingAmount = Coin.ZERO;
Coin sellersSpendingAmount = Coin.ZERO;
// Add optional taker outputs
for (TransactionOutput output : takerOutputs) {
// Add optional seller outputs
for (TransactionOutput output : sellerOutputs) {
preparedDepositTx.addOutput(output);
// subtract change amount
takersSpendingAmount = takersSpendingAmount.subtract(output.getValue());
sellersSpendingAmount = sellersSpendingAmount.subtract(output.getValue());
}
// Sign inputs (start after offerer inputs)
for (int i = offererConnectedOutputsForAllInputs.size(); i < preparedDepositTx.getInputs().size(); i++) {
// Sign inputs (start after buyer inputs)
for (int i = buyerConnectedOutputsForAllInputs.size(); i < preparedDepositTx.getInputs().size(); i++) {
TransactionInput input = preparedDepositTx.getInput(i);
signInput(preparedDepositTx, input, i);
checkScriptSig(preparedDepositTx, input, i);
// add up spending amount
assert input.getConnectedOutput() != null;
takersSpendingAmount = takersSpendingAmount.add(input.getConnectedOutput().getValue());
sellersSpendingAmount = sellersSpendingAmount.add(input.getConnectedOutput().getValue());
}
if (takerInputAmount.compareTo(takersSpendingAmount) != 0)
throw new TransactionVerificationException("Takers input amount does not match required value.");
if (sellerInputAmount.compareTo(sellersSpendingAmount) != 0)
throw new TransactionVerificationException("Sellers input amount does not match required value.");
verifyTransaction(preparedDepositTx);
printTxWithInputs("preparedDepositTx", preparedDepositTx);
return new Result(preparedDepositTx, takerConnectedOutputsForAllInputs, takerOutputs);
return new Result(preparedDepositTx, sellerConnectedOutputsForAllInputs, sellerOutputs);
}
public void signAndPublishDepositTx(Transaction preparedDepositTx,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> takerConnectedOutputsForAllInputs,
List<TransactionOutput> buyerConnectedOutputsForAllInputs,
List<TransactionOutput> sellerConnectedOutputsForAllInputs,
List<TransactionOutput> buyerOutputs,
Coin buyerInputAmount,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] buyerPubKey,
byte[] sellerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException,
WalletException {
log.trace("offererSignsAndPublishTx called");
log.trace("signAndPublishDepositTx called");
log.trace("preparedDepositTx " + preparedDepositTx.toString());
log.trace("offererConnectedOutputsForAllInputs " + offererConnectedOutputsForAllInputs.toString());
log.trace("takerConnectedOutputsForAllInputs " + takerConnectedOutputsForAllInputs.toString());
log.trace("buyerConnectedOutputsForAllInputs " + buyerConnectedOutputsForAllInputs.toString());
log.trace("sellerConnectedOutputsForAllInputs " + sellerConnectedOutputsForAllInputs.toString());
log.trace("buyerOutputs " + buyerOutputs.toString());
log.trace("buyerInputAmount " + buyerInputAmount.toFriendlyString());
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
checkArgument(offererConnectedOutputsForAllInputs.size() > 0);
checkArgument(takerConnectedOutputsForAllInputs.size() > 0);
checkArgument(buyerConnectedOutputsForAllInputs.size() > 0);
checkArgument(sellerConnectedOutputsForAllInputs.size() > 0);
// Check if takers Multisig script is identical to mine
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(offererPubKey, takerPubKey, arbitratorPubKey);
// Check if sellers Multisig script is identical to mine
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
if (!preparedDepositTx.getOutput(0).getScriptPubKey().equals(p2SHMultiSigOutputScript))
throw new TransactionVerificationException("Takers p2SHMultiSigOutputScript does not match to my p2SHMultiSigOutputScript");
throw new TransactionVerificationException("Sellers p2SHMultiSigOutputScript does not match to my p2SHMultiSigOutputScript");
// The outpoints are not available from the serialized preparedDepositTx, so we cannot use that tx directly, but we use it to construct a new
// depositTx
Transaction depositTx = new Transaction(params);
// Add offerer inputs
Coin offererSpendingAmount = Coin.ZERO;
for (TransactionOutput connectedOutputForInput : offererConnectedOutputsForAllInputs) {
// Add buyer inputs
Coin buyerSpendingAmount = Coin.ZERO;
for (TransactionOutput connectedOutputForInput : buyerConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
TransactionInput input = new TransactionInput(params, depositTx, new byte[]{}, outPoint, connectedOutputForInput.getValue());
depositTx.addInput(input);
// add up spending amount
assert input.getConnectedOutput() != null;
offererSpendingAmount = offererSpendingAmount.add(input.getConnectedOutput().getValue());
buyerSpendingAmount = buyerSpendingAmount.add(input.getConnectedOutput().getValue());
}
// Add taker inputs and apply signature
for (TransactionOutput connectedOutputForInput : takerConnectedOutputsForAllInputs) {
// Add seller inputs and apply signature
for (TransactionOutput connectedOutputForInput : sellerConnectedOutputsForAllInputs) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, connectedOutputForInput.getIndex(), connectedOutputForInput.getParentTransaction());
// We grab the signature from the preparedDepositTx and apply it to the new tx input
TransactionInput takerInput = preparedDepositTx.getInputs().get(offererConnectedOutputsForAllInputs.size());
byte[] scriptProgram = takerInput.getScriptSig().getProgram();
TransactionInput sellerInput = preparedDepositTx.getInputs().get(buyerConnectedOutputsForAllInputs.size());
byte[] scriptProgram = sellerInput.getScriptSig().getProgram();
if (scriptProgram.length == 0)
throw new TransactionVerificationException("Inputs from taker not singed.");
throw new TransactionVerificationException("Inputs from seller not singed.");
TransactionInput transactionInput = new TransactionInput(params, depositTx, scriptProgram, outPoint, connectedOutputForInput.getValue());
depositTx.addInput(transactionInput);
@ -372,7 +370,7 @@ public class TradeWalletService {
preparedDepositTx.getOutputs().forEach(depositTx::addOutput);
// Sign inputs
for (int i = 0; i < offererConnectedOutputsForAllInputs.size(); i++) {
for (int i = 0; i < buyerConnectedOutputsForAllInputs.size(); i++) {
TransactionInput input = depositTx.getInput(i);
signInput(depositTx, input, i);
checkScriptSig(depositTx, input, i);
@ -380,11 +378,11 @@ public class TradeWalletService {
// subtract change amount
for (int i = 1; i < buyerOutputs.size() + 1; i++) {
offererSpendingAmount = offererSpendingAmount.subtract(depositTx.getOutput(i).getValue());
buyerSpendingAmount = buyerSpendingAmount.subtract(depositTx.getOutput(i).getValue());
}
if (buyerInputAmount.compareTo(offererSpendingAmount) != 0)
throw new TransactionVerificationException("Offerers input amount does not match required value.");
if (buyerInputAmount.compareTo(buyerSpendingAmount) != 0)
throw new TransactionVerificationException("Buyers input amount does not match required value.");
verifyTransaction(depositTx);
checkWalletConsistency();
@ -417,94 +415,88 @@ public class TradeWalletService {
}
public byte[] createAndSignPayoutTx(Transaction depositTx,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
Coin buyerPayoutAmount,
Coin sellerPayoutAmount,
AddressEntry buyerAddressEntry,
String sellerPayoutAddressString,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] buyerPubKey,
byte[] sellerPubKey,
byte[] arbitratorPubKey)
throws AddressFormatException, TransactionVerificationException, SigningException {
log.trace("offererCreatesAndSignsPayoutTx called");
log.trace("createAndSignPayoutTx called");
log.trace("depositTx " + depositTx.toString());
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
log.trace("buyerAddressEntry " + buyerAddressEntry.toString());
log.trace("sellerPayoutAddressString " + sellerPayoutAddressString);
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
if (!Utils.HEX.encode(buyerAddressEntry.getPubKey()).equals(Utils.HEX.encode(offererPubKey)))
throw new SigningException("OffererPubKey not matching key pair from addressEntry");
Transaction preparedPayoutTx = createPayoutTx(depositTx,
offererPayoutAmount,
takerPayoutAmount,
buyerPayoutAmount,
sellerPayoutAmount,
buyerAddressEntry.getAddressString(),
sellerPayoutAddressString);
// MS redeemScript
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = buyerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
ECKey.ECDSASignature buyerSignature = buyerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
verifyTransaction(preparedPayoutTx);
printTxWithInputs("preparedPayoutTx", preparedPayoutTx);
log.trace("offererSignature r " + offererSignature.toCanonicalised().r.toString());
log.trace("offererSignature s " + offererSignature.toCanonicalised().s.toString());
log.trace("buyerSignature r " + buyerSignature.toCanonicalised().r.toString());
log.trace("buyerSignature s " + buyerSignature.toCanonicalised().s.toString());
Sha256Hash hashForSignature = preparedPayoutTx.hashForSignature(0, redeemScript.getProgram(), (byte) 1);
log.trace("hashForSignature " + Utils.HEX.encode(hashForSignature.getBytes()));
return offererSignature.encodeToDER();
return buyerSignature.encodeToDER();
}
public void signAndPublishPayoutTx(Transaction depositTx,
byte[] buyerSignature,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
Coin buyerPayoutAmount,
Coin sellerPayoutAmount,
String buyerAddressString,
AddressEntry sellerAddressEntry,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] buyerPubKey,
byte[] sellerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback)
throws AddressFormatException, TransactionVerificationException, WalletException, SigningException {
log.trace("takerSignsAndPublishPayoutTx called");
log.trace("signAndPublishPayoutTx called");
log.trace("depositTx " + depositTx.toString());
log.trace("buyerSignature r " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).r.toString());
log.trace("buyerSignature s " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).s.toString());
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
log.trace("buyerAddressString " + buyerAddressString);
log.trace("sellerAddressEntry " + sellerAddressEntry);
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
if (!Utils.HEX.encode(sellerAddressEntry.getPubKey()).equals(Utils.HEX.encode(takerPubKey)))
throw new SigningException("TakerPubKey not matching key pair from addressEntry");
Transaction payoutTx = createPayoutTx(depositTx,
offererPayoutAmount,
takerPayoutAmount,
buyerPayoutAmount,
sellerPayoutAmount,
buyerAddressString,
sellerAddressEntry.getAddressString());
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature takerSignature = sellerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
ECKey.ECDSASignature sellerSignature = sellerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
log.trace("takerSignature r " + takerSignature.r.toString());
log.trace("takerSignature s " + takerSignature.s.toString());
log.trace("sellerSignature r " + sellerSignature.r.toString());
log.trace("sellerSignature s " + sellerSignature.s.toString());
Sha256Hash hashForSignature = payoutTx.hashForSignature(0, redeemScript.getProgram(), (byte) 1);
log.trace("hashForSignature " + Utils.HEX.encode(hashForSignature.getBytes()));
TransactionSignature offererTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(buyerSignature),
TransactionSignature buyerTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(buyerSignature),
Transaction.SigHash.ALL, false);
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
TransactionSignature sellerTxSig = new TransactionSignature(sellerSignature, Transaction.SigHash.ALL, false);
// Take care of order of signatures. See comment below at getMultiSigRedeemScript
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(takerTxSig, offererTxSig), redeemScript);
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(sellerTxSig, buyerTxSig), redeemScript);
TransactionInput input = payoutTx.getInput(0);
input.setScriptSig(inputScript);
@ -533,30 +525,30 @@ public class TradeWalletService {
// Furthermore the executed list is reversed to the provided.
// Best practice is to provide the list sorted by the least probable successful candidates first (arbitrator is first -> will be last in execution loop, so
// avoiding unneeded expensive ECKey.verify calls)
private Script getMultiSigRedeemScript(byte[] offererPubKey, byte[] takerPubKey, byte[] arbitratorPubKey) {
ECKey offererKey = ECKey.fromPublicOnly(offererPubKey);
ECKey takerKey = ECKey.fromPublicOnly(takerPubKey);
private Script getMultiSigRedeemScript(byte[] buyerPubKey, byte[] sellerPubKey, byte[] arbitratorPubKey) {
ECKey buyerKey = ECKey.fromPublicOnly(buyerPubKey);
ECKey sellerKey = ECKey.fromPublicOnly(sellerPubKey);
ECKey arbitratorKey = ECKey.fromPublicOnly(arbitratorPubKey);
// Take care of sorting!
List<ECKey> keys = ImmutableList.of(arbitratorKey, takerKey, offererKey);
List<ECKey> keys = ImmutableList.of(arbitratorKey, sellerKey, buyerKey);
return ScriptBuilder.createMultiSigOutputScript(2, keys);
}
private Script getP2SHMultiSigOutputScript(byte[] offererPubKey, byte[] takerPubKey, byte[] arbitratorPubKey) {
return ScriptBuilder.createP2SHOutputScript(getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey));
private Script getP2SHMultiSigOutputScript(byte[] buyerPubKey, byte[] sellerPubKey, byte[] arbitratorPubKey) {
return ScriptBuilder.createP2SHOutputScript(getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey));
}
private Transaction createPayoutTx(Transaction depositTx,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
String offererAddressString,
String takerAddressString) throws AddressFormatException {
Coin buyerPayoutAmount,
Coin sellerPayoutAmount,
String buyerAddressString,
String sellerAddressString) throws AddressFormatException {
TransactionOutput p2SHMultiSigOutput = depositTx.getOutput(0);
Transaction transaction = new Transaction(params);
transaction.addInput(p2SHMultiSigOutput);
transaction.addOutput(offererPayoutAmount, new Address(params, offererAddressString));
transaction.addOutput(takerPayoutAmount, new Address(params, takerAddressString));
transaction.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString));
transaction.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString));
return transaction;
}
@ -657,7 +649,7 @@ public class TradeWalletService {
private Transaction depositTx;
private byte[] offererSignature;
private byte[] buyerSignature;
public Result(List<TransactionOutput> connectedOutputsForAllInputs, List<TransactionOutput> outputs) {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
@ -682,8 +674,8 @@ public class TradeWalletService {
return depositTx;
}
public byte[] getOffererSignature() {
return offererSignature;
public byte[] getBuyerSignature() {
return buyerSignature;
}
}
}

View File

@ -64,7 +64,7 @@ public class OffererAsBuyerSubView extends TradeSubView {
leftVBox.getChildren().addAll(waitTxInBlockchain, startFiat, waitFiatReceived, completed);
}
///////////////////////////////////////////////////////////////////////////////////////////
// State
@ -78,8 +78,10 @@ public class OffererAsBuyerSubView extends TradeSubView {
startFiat.inactive();
waitFiatReceived.inactive();
completed.inactive();
switch (viewState) {
case EMPTY:
break;
case OFFERER_BUYER_WAIT_TX_CONF:
showItem(waitTxInBlockchain);
@ -126,7 +128,11 @@ public class OffererAsBuyerSubView extends TradeSubView {
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
break;
case EXCEPTION:
Popups.openExceptionPopup(model.getTradeException());
if (model.getTradeException() != null)
Popups.openExceptionPopup(model.getTradeException());
break;
default:
log.warn("unhandled viewState " + viewState);
break;
}

View File

@ -0,0 +1,158 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.main.portfolio.pending.steps.CompletedView;
import io.bitsquare.gui.main.portfolio.pending.steps.ConfirmFiatReceivedView;
import io.bitsquare.gui.main.portfolio.pending.steps.TradeWizardItem;
import io.bitsquare.gui.main.portfolio.pending.steps.WaitTxInBlockchainView;
import io.bitsquare.locale.BSResources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererAsSellerSubView extends TradeSubView {
private static final Logger log = LoggerFactory.getLogger(OffererAsSellerSubView.class);
private TradeWizardItem waitTxInBlockchain;
private TradeWizardItem waitFiatStarted;
private TradeWizardItem confirmFiatReceived;
private TradeWizardItem completed;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, Initialisation
///////////////////////////////////////////////////////////////////////////////////////////
public OffererAsSellerSubView(PendingTradesViewModel model) {
super(model);
}
@Override
public void activate() {
super.activate();
}
@Override
public void deactivate() {
super.deactivate();
}
@Override
protected void addWizards() {
waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation");
waitFiatStarted = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for payment started");
confirmFiatReceived = new TradeWizardItem(ConfirmFiatReceivedView.class, "Confirm payment received");
completed = new TradeWizardItem(CompletedView.class, "Completed");
leftVBox.getChildren().addAll(waitTxInBlockchain, waitFiatStarted, confirmFiatReceived, completed);
}
///////////////////////////////////////////////////////////////////////////////////////////
// State
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void applyState(PendingTradesViewModel.ViewState viewState) {
log.debug("applyState " + viewState);
waitTxInBlockchain.inactive();
waitFiatStarted.inactive();
confirmFiatReceived.inactive();
completed.inactive();
switch (viewState) {
case EMPTY:
break;
case OFFERER_SELLER_WAIT_TX_CONF:
showItem(waitTxInBlockchain);
((WaitTxInBlockchainView) tradeStepDetailsView).setInfoLabelText("Deposit transaction has been published. " +
"The Bitcoin buyer need to wait for at least one block chain confirmation.");
((WaitTxInBlockchainView) tradeStepDetailsView).setInfoDisplayField(BSResources.get("The Bitcoin buyer needs to wait for at least one " +
"block chain confirmation before starting the {0} payment. " +
"That is needed to assure that the deposit input funding has not been " +
"double-spent. " +
"For higher trade volumes it is recommended to wait up to 6 confirmations.",
model.getCurrencyCode()));
break;
case OFFERER_SELLER_WAIT_PAYMENT_STARTED:
waitTxInBlockchain.done();
showItem(waitFiatStarted);
((WaitTxInBlockchainView) tradeStepDetailsView).setInfoLabelText(BSResources.get("Deposit transaction has at least one block chain " +
"confirmation. " +
"Waiting that other trader starts the {0} payment.",
model.getCurrencyCode()));
((WaitTxInBlockchainView) tradeStepDetailsView).setInfoDisplayField(BSResources.get("You will get informed when the other trader has " +
"indicated the {0} payment has been started.",
model.getCurrencyCode()));
break;
case OFFERER_SELLER_CONFIRM_RECEIVE_PAYMENT:
waitTxInBlockchain.done();
waitFiatStarted.done();
showItem(confirmFiatReceived);
((ConfirmFiatReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("The Bitcoin buyer has started the {0} payment." +
"Check your payments account and confirm when you have received the payment.",
model.getCurrencyCode()));
((ConfirmFiatReceivedView) tradeStepDetailsView).setInfoDisplayField(BSResources.get("It is important that you confirm when you have " +
"received the {0} payment as this will publish the payout transaction where you get returned " +
"your security deposit and the Bitcoin buyer receive the Bitcoin amount you sold.",
model.getCurrencyCode()));
break;
case OFFERER_SELLER_COMPLETED:
waitTxInBlockchain.done();
waitFiatStarted.done();
confirmFiatReceived.done();
showItem(completed);
CompletedView completedView = (CompletedView) tradeStepDetailsView;
completedView.setBtcTradeAmountLabelText("You have sold:");
completedView.setFiatTradeAmountLabelText("You have received:");
completedView.setBtcTradeAmountTextFieldText(model.getTradeVolume());
completedView.setFiatTradeAmountTextFieldText(model.getFiatVolume());
completedView.setFeesTextFieldText(model.getTotalFees());
completedView.setSecurityDepositTextFieldText(model.getSecurityDeposit());
completedView.setSummaryInfoDisplayText("Your security deposit has been refunded to you. " +
"You can review the details to that trade any time in the closed trades screen.");
completedView.setWithdrawAmountTextFieldText(model.getAmountToWithdraw());
break;
case MESSAGE_SENDING_FAILED:
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
break;
case EXCEPTION:
if (model.getTradeException() != null)
Popups.openExceptionPopup(model.getTradeException());
break;
default:
log.warn("unhandled viewState " + viewState);
break;
}
if (tradeStepDetailsView != null)
tradeStepDetailsView.activate();
}
}

View File

@ -25,9 +25,9 @@ import io.bitsquare.gui.components.Popups;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User;
@ -68,8 +68,11 @@ class PendingTradesDataModel implements Activatable, DataModel {
final StringProperty txId = new SimpleStringProperty();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<Trade.ProcessState> takerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade.ProcessState> offererProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade.ProcessState> takerAsSellerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade.ProcessState> offererAsBuyerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade.ProcessState> takerAsBuyerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade.ProcessState> offererAsSellerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<Trade> currentTrade = new SimpleObjectProperty<>();
@Inject
@ -95,7 +98,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
@Override
public void deactivate() {
tradeManager.getPendingTrades().removeListener(tradesListChangeListener);
removeListenerFromSelectedTrade();
unbindStates();
}
private void onListChanged() {
@ -111,17 +114,20 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
}
boolean isBuyOffer() {
if (getTrade() != null)
return getTrade().getOffer().getDirection() == Offer.Direction.BUY;
else
return false;
}
void selectTrade(PendingTradesListItem item) {
// clean up previous selectedItem
removeListenerFromSelectedTrade();
unbindStates();
selectedItem = item;
if (item == null) {
if (currentTrade != null) {
takerProcessState.unbind();
offererProcessState.unbind();
}
currentTrade.set(null);
}
else {
@ -130,9 +136,13 @@ class PendingTradesDataModel implements Activatable, DataModel {
Trade trade = item.getTrade();
isOfferer = trade.getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
if (trade instanceof TakerAsSellerTrade)
takerProcessState.bind(trade.processStateProperty());
else
offererProcessState.bind(trade.processStateProperty());
takerAsSellerProcessState.bind(trade.processStateProperty());
else if (trade instanceof OffererAsBuyerTrade)
offererAsBuyerProcessState.bind(trade.processStateProperty());
else if (trade instanceof TakerAsBuyerTrade)
takerAsBuyerProcessState.bind(trade.processStateProperty());
else if (trade instanceof OffererAsSellerTrade)
offererAsSellerProcessState.bind(trade.processStateProperty());
if (trade.getDepositTx() != null)
txId.set(trade.getDepositTx().getHashAsString());
@ -140,13 +150,17 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
void fiatPaymentStarted() {
if (getTrade() != null)
if (getTrade() instanceof OffererAsBuyerTrade)
((OffererAsBuyerTrade) getTrade()).onFiatPaymentStarted();
else if (getTrade() instanceof TakerAsBuyerTrade)
((TakerAsBuyerTrade) getTrade()).onFiatPaymentStarted();
}
void fiatPaymentReceived() {
if (getTrade() != null)
if (getTrade() instanceof TakerAsSellerTrade)
((TakerAsSellerTrade) getTrade()).onFiatPaymentReceived();
else if (getTrade() instanceof OffererAsSellerTrade)
((OffererAsSellerTrade) getTrade()).onFiatPaymentReceived();
}
void withdraw(String toAddress) {
@ -237,21 +251,18 @@ class PendingTradesDataModel implements Activatable, DataModel {
offer.getDirection() : offer.getMirroredDirection();
}
private void removeListenerFromSelectedTrade() {
if (selectedItem != null) {
Trade trade = selectedItem.getTrade();
if (trade instanceof TakerTrade)
takerProcessState.unbind();
else
offererProcessState.unbind();
}
private void unbindStates() {
takerAsSellerProcessState.unbind();
takerAsBuyerProcessState.unbind();
offererAsBuyerProcessState.unbind();
offererAsSellerProcessState.unbind();
}
public Coin getAmountToWithdraw() {
Trade trade = selectedItem.getTrade();
Coin amountToWithdraw = trade.getSecurityDeposit();
assert trade.getTradeAmount() != null;
if (trade instanceof OffererTrade)
if (trade instanceof OffererAsBuyerTrade || trade instanceof TakerAsBuyerTrade)
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
return amountToWithdraw;
}

View File

@ -106,7 +106,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
else {
removeSubView();
}
if (currentSubView != null)
currentSubView.activate();
}
@ -127,13 +127,20 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
private void addSubView() {
removeSubView();
if (model.isOfferer())
currentSubView = new OffererAsBuyerSubView(model);
else
currentSubView = new TakerAsSellerSubView(model);
if (model.isOfferer()) {
if (model.isBuyOffer())
currentSubView = new OffererAsBuyerSubView(model);
else
currentSubView = new OffererAsSellerSubView(model);
}
else {
if (model.isBuyOffer())
currentSubView = new TakerAsSellerSubView(model);
else
currentSubView = new TakerAsBuyerSubView(model);
}
currentSubView.activate();
AnchorPane.setTopAnchor(currentSubView, 0d);
AnchorPane.setRightAnchor(currentSubView, 0d);
AnchorPane.setBottomAnchor(currentSubView, 0d);

View File

@ -58,6 +58,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
private static final Logger log = LoggerFactory.getLogger(PendingTradesViewModel.class);
enum ViewState {
EMPTY,
TAKER_SELLER_WAIT_TX_CONF,
TAKER_SELLER_WAIT_PAYMENT_STARTED,
TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT,
@ -68,20 +69,34 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED,
OFFERER_BUYER_COMPLETED,
TAKER_BUYER_WAIT_TX_CONF,
TAKER_BUYER_START_PAYMENT,
TAKER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED,
TAKER_BUYER_COMPLETED,
OFFERER_SELLER_WAIT_TX_CONF,
OFFERER_SELLER_WAIT_PAYMENT_STARTED,
OFFERER_SELLER_CONFIRM_RECEIVE_PAYMENT,
OFFERER_SELLER_COMPLETED,
MESSAGE_SENDING_FAILED,
EXCEPTION
}
private Navigation navigation;
private final BSFormatter formatter;
private final InvalidationListener takerStateListener;
private final InvalidationListener offererStateListener;
private final InvalidationListener takerAsSellerStateListener;
private final InvalidationListener offererAsBuyerStateListener;
private final InvalidationListener takerAsBuyerStateListener;
private final InvalidationListener offererAsSellerStateListener;
private final BtcAddressValidator btcAddressValidator;
public final StringProperty txId = new SimpleStringProperty();
public final BooleanProperty withdrawalButtonDisable = new SimpleBooleanProperty(true);
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<ViewState> viewState = new SimpleObjectProperty<>();
final ObjectProperty<ViewState> viewState = new SimpleObjectProperty<>(ViewState.EMPTY);
@Inject
@ -92,8 +107,10 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
this.formatter = formatter;
this.btcAddressValidator = btcAddressValidator;
this.takerStateListener = (ov) -> updateTakerState();
this.offererStateListener = (ov) -> updateOffererState();
this.takerAsSellerStateListener = (ov) -> updateTakerAsSellerState();
this.offererAsBuyerStateListener = (ov) -> updateOffererAsBuyerState();
this.takerAsBuyerStateListener = (ov) -> updateTakerAsBuyerState();
this.offererAsSellerStateListener = (ov) -> updateOffererAsSellerState();
}
@Override
@ -101,11 +118,15 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
txId.bind(dataModel.txId);
selectedIndex.bind(dataModel.selectedIndex);
dataModel.takerProcessState.addListener(takerStateListener);
dataModel.offererProcessState.addListener(offererStateListener);
dataModel.takerAsSellerProcessState.addListener(takerAsSellerStateListener);
dataModel.offererAsBuyerProcessState.addListener(offererAsBuyerStateListener);
dataModel.takerAsBuyerProcessState.addListener(takerAsBuyerStateListener);
dataModel.offererAsSellerProcessState.addListener(offererAsSellerStateListener);
updateTakerState();
updateOffererState();
updateTakerAsSellerState();
updateOffererAsBuyerState();
updateTakerAsBuyerState();
updateOffererAsSellerState();
}
@Override
@ -113,17 +134,22 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
txId.unbind();
selectedIndex.unbind();
dataModel.takerProcessState.removeListener(takerStateListener);
dataModel.offererProcessState.removeListener(offererStateListener);
dataModel.takerAsSellerProcessState.removeListener(takerAsSellerStateListener);
dataModel.offererAsBuyerProcessState.removeListener(offererAsBuyerStateListener);
dataModel.takerAsBuyerProcessState.removeListener(takerAsBuyerStateListener);
dataModel.offererAsSellerProcessState.removeListener(offererAsSellerStateListener);
}
void selectTrade(PendingTradesListItem item) {
dataModel.selectTrade(item);
/* updateTakerState();
updateOffererState();*/
}
boolean isBuyOffer() {
return dataModel.isBuyOffer();
}
public void fiatPaymentStarted() {
dataModel.fiatPaymentStarted();
}
@ -141,7 +167,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
withdrawalButtonDisable.set(!btcAddressValidator.validate(text).isValid);
}
public String getAmountToWithdraw() {
public String getAmountToWithdraw() {
return formatter.formatCoinWithCode(dataModel.getAmountToWithdraw());
}
@ -191,7 +217,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
}
// payment
public String getPaymentMethod() {
public String getPaymentMethod() {
assert dataModel.getContract() != null;
return BSResources.get(dataModel.getContract().takerFiatAccount.type.toString());
}
@ -200,27 +226,27 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
return formatter.formatFiatWithCode(dataModel.getTrade().getTradeVolume());
}
public String getHolderName() {
public String getHolderName() {
assert dataModel.getContract() != null;
return dataModel.getContract().takerFiatAccount.accountHolderName;
}
public String getPrimaryId() {
public String getPrimaryId() {
assert dataModel.getContract() != null;
return dataModel.getContract().takerFiatAccount.accountPrimaryID;
}
public String getSecondaryId() {
public String getSecondaryId() {
assert dataModel.getContract() != null;
return dataModel.getContract().takerFiatAccount.accountSecondaryID;
}
// summary
public String getTradeVolume() {
public String getTradeVolume() {
return formatter.formatCoinWithCode(dataModel.getTrade().getTradeAmount());
}
public String getFiatVolume() {
public String getFiatVolume() {
return formatter.formatFiatWithCode(dataModel.getTrade().getTradeVolume());
}
@ -249,160 +275,163 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
return dataModel.getErrorMessage();
}
private void updateTakerState() {
if (dataModel.getTrade() instanceof TakerAsSellerTrade) {
TakerAsSellerTrade.ProcessState processState = (TakerAsSellerTrade.ProcessState) dataModel.takerProcessState.get();
log.debug("updateTakerState " + processState);
if (processState != null) {
switch (processState) {
case TAKE_OFFER_FEE_TX_CREATED:
break;
case TAKE_OFFER_FEE_PUBLISHED:
break;
case TAKE_OFFER_FEE_PUBLISH_FAILED:
break;
private void updateTakerAsSellerState() {
TakerAsSellerTrade.ProcessState processState = (TakerAsSellerTrade.ProcessState) dataModel.takerAsSellerProcessState.get();
log.debug("updateTakerAsSellerState " + processState);
if (processState != null) {
switch (processState) {
case UNDEFINED:
case TAKE_OFFER_FEE_TX_CREATED:
case TAKE_OFFER_FEE_PUBLISHED:
break;
case TAKE_OFFER_FEE_PUBLISH_FAILED:
viewState.set(ViewState.EXCEPTION);
break;
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.TAKER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break;
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.TAKER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case FIAT_PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED:
viewState.set(ViewState.TAKER_SELLER_COMPLETED);
break;
case FIAT_PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED:
viewState.set(ViewState.TAKER_SELLER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled processState " + processState);
break;
}
default:
log.warn("unhandled processState " + processState);
break;
}
}
else if (dataModel.getTrade() instanceof TakerAsBuyerTrade) {
TakerAsBuyerTrade.ProcessState processState = (TakerAsBuyerTrade.ProcessState) dataModel.takerProcessState.get();
log.debug("updateTakerState " + processState);
if (processState != null) {
switch (processState) {
case TAKE_OFFER_FEE_TX_CREATED:
break;
case TAKE_OFFER_FEE_PUBLISHED:
break;
case TAKE_OFFER_FEE_PUBLISH_FAILED:
break;
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.TAKER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case FIAT_PAYMENT_RECEIVED:
viewState.set(ViewState.TAKER_SELLER_COMPLETED);
break;
case PAYOUT_PUBLISHED:
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled processState " + processState);
break;
}
}
}
}
private void updateOffererState() {
if (dataModel.getTrade() instanceof OffererAsBuyerTrade) {
OffererAsBuyerTrade.ProcessState processState = (OffererAsBuyerTrade.ProcessState) dataModel.offererProcessState.get();
log.debug("updateOffererState " + processState);
if (processState != null) {
switch (processState) {
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.OFFERER_BUYER_START_PAYMENT);
break;
private void updateOffererAsBuyerState() {
OffererAsBuyerTrade.ProcessState processState = (OffererAsBuyerTrade.ProcessState) dataModel.offererAsBuyerProcessState.get();
log.debug("updateOffererAsBuyerState " + processState);
if (processState != null) {
switch (processState) {
case UNDEFINED:
break;
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.OFFERER_BUYER_START_PAYMENT);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
break;
case PAYOUT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_COMPLETED);
break;
case PAYOUT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled viewState " + processState);
break;
}
default:
log.warn("unhandled viewState " + processState);
break;
}
}
else if (dataModel.getTrade() instanceof OffererAsSellerTrade) {
OffererAsSellerTrade.ProcessState processState = (OffererAsSellerTrade.ProcessState) dataModel.offererProcessState.get();
log.debug("updateOffererState " + processState);
if (processState != null) {
switch (processState) {
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.OFFERER_BUYER_START_PAYMENT);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
break;
case PAYOUT_PUBLISHED:
viewState.set(ViewState.OFFERER_BUYER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled viewState " + processState);
break;
}
}
}
}
private void updateTakerAsBuyerState() {
TakerAsBuyerTrade.ProcessState processState = (TakerAsBuyerTrade.ProcessState) dataModel.takerAsBuyerProcessState.get();
log.debug("updateTakerAsBuyerState " + processState);
if (processState != null) {
switch (processState) {
case UNDEFINED:
case TAKE_OFFER_FEE_TX_CREATED:
case TAKE_OFFER_FEE_PUBLISHED:
break;
case TAKE_OFFER_FEE_PUBLISH_FAILED:
viewState.set(ViewState.EXCEPTION);
break;
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.TAKER_BUYER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.TAKER_BUYER_START_PAYMENT);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.TAKER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
break;
case FIAT_PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED:
viewState.set(ViewState.TAKER_BUYER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled viewState " + processState);
break;
}
}
}
private void updateOffererAsSellerState() {
OffererAsSellerTrade.ProcessState processState = (OffererAsSellerTrade.ProcessState) dataModel.offererAsSellerProcessState.get();
log.debug("updateOffererAsSellerState " + processState);
if (processState != null) {
switch (processState) {
case UNDEFINED:
break;
case DEPOSIT_PUBLISHED:
viewState.set(ViewState.OFFERER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
viewState.set(ViewState.OFFERER_SELLER_WAIT_PAYMENT_STARTED);
break;
case FIAT_PAYMENT_STARTED:
viewState.set(ViewState.OFFERER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case FIAT_PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED:
viewState.set(ViewState.OFFERER_SELLER_COMPLETED);
break;
case MESSAGE_SENDING_FAILED:
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
break;
case EXCEPTION:
viewState.set(ViewState.EXCEPTION);
break;
default:
log.warn("unhandled processState " + processState);
break;
}
}
}
}

View File

@ -0,0 +1,146 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.main.portfolio.pending.steps.CompletedView;
import io.bitsquare.gui.main.portfolio.pending.steps.StartFiatView;
import io.bitsquare.gui.main.portfolio.pending.steps.TradeWizardItem;
import io.bitsquare.gui.main.portfolio.pending.steps.WaitFiatReceivedView;
import io.bitsquare.gui.main.portfolio.pending.steps.WaitTxInBlockchainView;
import io.bitsquare.locale.BSResources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerAsBuyerSubView extends TradeSubView {
private static final Logger log = LoggerFactory.getLogger(TakerAsBuyerSubView.class);
private TradeWizardItem waitTxInBlockchain;
private TradeWizardItem startFiat;
private TradeWizardItem waitFiatReceived;
private TradeWizardItem completed;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, Initialisation
///////////////////////////////////////////////////////////////////////////////////////////
public TakerAsBuyerSubView(PendingTradesViewModel model) {
super(model);
}
@Override
public void activate() {
super.activate();
}
@Override
public void deactivate() {
super.deactivate();
}
@Override
protected void addWizards() {
waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation");
startFiat = new TradeWizardItem(StartFiatView.class, "Start payment");
waitFiatReceived = new TradeWizardItem(WaitFiatReceivedView.class, "Wait until payment has arrived");
completed = new TradeWizardItem(CompletedView.class, "Completed");
leftVBox.getChildren().addAll(waitTxInBlockchain, startFiat, waitFiatReceived, completed);
}
///////////////////////////////////////////////////////////////////////////////////////////
// State
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void applyState(PendingTradesViewModel.ViewState viewState) {
log.debug("applyState " + viewState);
waitTxInBlockchain.inactive();
startFiat.inactive();
waitFiatReceived.inactive();
completed.inactive();
switch (viewState) {
case EMPTY:
break;
case TAKER_BUYER_WAIT_TX_CONF:
showItem(waitTxInBlockchain);
((WaitTxInBlockchainView) tradeStepDetailsView).setInfoLabelText("Deposit transaction has been published. You need to wait for at least " +
"one block chain confirmation.");
((WaitTxInBlockchainView) tradeStepDetailsView).setInfoDisplayField("You need to wait for at least one block chain confirmation to" +
" be sure that the deposit funding has not been double spent. For higher trade volumes we" +
" recommend to wait up to 6 confirmations.");
break;
case TAKER_BUYER_START_PAYMENT:
waitTxInBlockchain.done();
showItem(startFiat);
break;
case TAKER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED:
waitTxInBlockchain.done();
startFiat.done();
showItem(waitFiatReceived);
((WaitFiatReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("Waiting for the Bitcoin sellers confirmation " +
"that the {0} payment has arrived.",
model.getCurrencyCode()));
((WaitFiatReceivedView) tradeStepDetailsView).setInfoDisplayField(BSResources.get("When the confirmation that the {0} payment arrived at " +
"the Bitcoin sellers payment account, the payout transaction will be published.",
model.getCurrencyCode()));
break;
case TAKER_BUYER_COMPLETED:
waitTxInBlockchain.done();
startFiat.done();
waitFiatReceived.done();
showItem(completed);
CompletedView completedView = (CompletedView) tradeStepDetailsView;
completedView.setBtcTradeAmountLabelText("You have bought:");
completedView.setFiatTradeAmountLabelText("You have paid:");
completedView.setBtcTradeAmountTextFieldText(model.getTradeVolume());
completedView.setFiatTradeAmountTextFieldText(model.getFiatVolume());
completedView.setFeesTextFieldText(model.getTotalFees());
completedView.setSecurityDepositTextFieldText(model.getSecurityDeposit());
completedView.setSummaryInfoDisplayText("Your security deposit has been refunded to you. " +
"You can review the details to that trade any time in the closed trades screen.");
completedView.setWithdrawAmountTextFieldText(model.getAmountToWithdraw());
break;
case MESSAGE_SENDING_FAILED:
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
break;
case EXCEPTION:
if (model.getTradeException() != null)
Popups.openExceptionPopup(model.getTradeException());
break;
default:
log.warn("unhandled viewState " + viewState);
break;
}
if (tradeStepDetailsView != null)
tradeStepDetailsView.activate();
}
}

View File

@ -79,6 +79,8 @@ public class TakerAsSellerSubView extends TradeSubView {
completed.inactive();
switch (viewState) {
case EMPTY:
break;
case TAKER_SELLER_WAIT_TX_CONF:
showItem(waitTxInBlockchain);
@ -141,10 +143,14 @@ public class TakerAsSellerSubView extends TradeSubView {
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
break;
case EXCEPTION:
Popups.openExceptionPopup(model.getTradeException());
if (model.getTradeException() != null)
Popups.openExceptionPopup(model.getTradeException());
break;
default:
log.warn("unhandled viewState " + viewState);
break;
}
if (tradeStepDetailsView != null)
tradeStepDetailsView.activate();
}

View File

@ -54,7 +54,7 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, EncryptionService<MailboxMessage> encryptionService) {
public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, EncryptionService<MailboxMessage> encryptionService) {
super(tomP2PNode);
this.mailboxService = mailboxService;
this.encryptionService = encryptionService;
@ -80,7 +80,10 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
@Override
public void sendMessage(Peer peer, Message message, PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey,
SendMessageListener listener) {
if (!(peer instanceof TomP2PPeer))
if (peer == null)
throw new IllegalArgumentException("Peer must not be null");
else if (!(peer instanceof TomP2PPeer))
throw new IllegalArgumentException("Peer must be of type TomP2PPeer");
FutureDirect futureDirect = peerDHT.peer().sendDirect(((TomP2PPeer) peer).getPeerAddress()).object(message).start();

View File

@ -101,6 +101,7 @@ public class TakerAsBuyerTrade extends TakerTrade implements Serializable {
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void takeAvailableOffer() {
assert protocol instanceof TakerAsBuyerProtocol;
((TakerAsBuyerProtocol) protocol).takeAvailableOffer();

View File

@ -101,6 +101,7 @@ public class TakerAsSellerTrade extends TakerTrade implements Serializable {
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void takeAvailableOffer() {
assert protocol instanceof TakerAsSellerProtocol;
((TakerAsSellerProtocol) protocol).takeAvailableOffer();

View File

@ -95,6 +95,15 @@ public abstract class TakerTrade extends Trade implements Serializable {
return new TakerProcessModel();
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
abstract public void takeAvailableOffer();
///////////////////////////////////////////////////////////////////////////////////////////
// Getter only
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -91,7 +91,7 @@ public class TradeManager {
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
private final Storage<TradeList> pendingTradesStorage;
private final Storage<TradeList> openOfferTradesStorage;
private final TradeList<OffererAsBuyerTrade> openOfferTrades;
private final TradeList<OffererTrade> openOfferTrades;
private final TradeList<Trade> pendingTrades;
private final TradeList<Trade> closedTrades;
@ -150,15 +150,15 @@ public class TradeManager {
// When all services are initialized we create the protocols for our open offers and persisted pendingTrades
// OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early.
public void onAllServicesInitialized() {
for (OffererAsBuyerTrade OffererAsBuyerTrade : openOfferTrades) {
Offer offer = OffererAsBuyerTrade.getOffer();
for (OffererTrade offererTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer();
// We add own offers to offerbook when we go online again
offerBookService.addOffer(offer,
() -> log.debug("Successful removed open offer from DHT"),
(message, throwable) -> log.error("Remove open offer from DHT failed. " + message));
setupDepositPublishedListener(OffererAsBuyerTrade);
OffererAsBuyerTrade.setStorage(openOfferTradesStorage);
initTrade(OffererAsBuyerTrade);
setupDepositPublishedListener(offererTrade);
offererTrade.setStorage(openOfferTradesStorage);
initTrade(offererTrade);
}
List<Trade> failedTrades = new ArrayList<>();
@ -168,12 +168,11 @@ public class TradeManager {
// continue the trade, but that might fail.
boolean failed = false;
if (trade instanceof TakerAsSellerTrade) {
if (trade instanceof TakerAsSellerTrade)
failed = trade.lifeCycleState == TakerAsSellerTrade.LifeCycleState.FAILED;
}
else if (trade instanceof TakerAsBuyerTrade) {
else if (trade instanceof TakerAsBuyerTrade)
failed = trade.lifeCycleState == TakerAsBuyerTrade.LifeCycleState.FAILED;
}
if (failed) {
failedTrades.add(trade);
}
@ -229,8 +228,8 @@ public class TradeManager {
log.debug("shutDown");
shutDownRequested = true;
// we remove own offers form offerbook when we go offline
for (OffererAsBuyerTrade OffererAsBuyerTrade : openOfferTrades) {
Offer offer = OffererAsBuyerTrade.getOffer();
for (OffererTrade offererTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer();
offerBookService.removeOfferAtShutDown(offer);
}
}
@ -277,23 +276,28 @@ public class TradeManager {
}
private void handlePlaceOfferResult(Transaction transaction, Offer offer, TransactionResultHandler resultHandler) {
OffererAsBuyerTrade offererAsBuyerTrade = new OffererAsBuyerTrade(offer, openOfferTradesStorage);
openOfferTrades.add(offererAsBuyerTrade);
initTrade(offererAsBuyerTrade);
setupDepositPublishedListener(offererAsBuyerTrade);
OffererTrade offererTrade;
if (offer.getDirection() == Offer.Direction.BUY)
offererTrade = new OffererAsBuyerTrade(offer, openOfferTradesStorage);
else
offererTrade = new OffererAsSellerTrade(offer, openOfferTradesStorage);
openOfferTrades.add(offererTrade);
initTrade(offererTrade);
setupDepositPublishedListener(offererTrade);
resultHandler.handleResult(transaction);
}
private void setupDepositPublishedListener(OffererAsBuyerTrade offererAsBuyerTrade) {
offererAsBuyerTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("OffererAsBuyerTrade state = " + newValue);
if (newValue == OffererAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED) {
removeOpenOffer(offererAsBuyerTrade.getOffer(),
private void setupDepositPublishedListener(OffererTrade offererTrade) {
offererTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("setupDepositPublishedListener state = " + newValue);
if (newValue == OffererAsBuyerTrade.ProcessState.DEPOSIT_PUBLISHED || newValue == OffererAsSellerTrade.ProcessState.DEPOSIT_PUBLISHED) {
removeOpenOffer(offererTrade.getOffer(),
() -> log.debug("remove offer was successful"),
log::error,
false);
pendingTrades.add(offererAsBuyerTrade);
offererAsBuyerTrade.setStorage(pendingTradesStorage);
pendingTrades.add(offererTrade);
offererTrade.setStorage(pendingTradesStorage);
}
});
}
@ -309,15 +313,18 @@ public class TradeManager {
offerBookService.removeOffer(offer,
() -> {
offer.setState(Offer.State.REMOVED);
Optional<OffererAsBuyerTrade> OffererAsBuyerTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny();
if (OffererAsBuyerTradeOptional.isPresent()) {
OffererAsBuyerTrade offererAsBuyerTrade = OffererAsBuyerTradeOptional.get();
openOfferTrades.remove(offererAsBuyerTrade);
Optional<OffererTrade> offererTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny();
if (offererTradeOptional.isPresent()) {
OffererTrade offererTrade = offererTradeOptional.get();
openOfferTrades.remove(offererTrade);
if (isCancelRequest) {
offererAsBuyerTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_CANCELED);
closedTrades.add(offererAsBuyerTrade);
offererAsBuyerTrade.disposeProtocol();
if (offererTrade instanceof OffererAsBuyerTrade)
offererTrade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.OFFER_CANCELED);
else if (offererTrade instanceof OffererAsSellerTrade)
offererTrade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.OFFER_CANCELED);
closedTrades.add(offererTrade);
offererTrade.disposeProtocol();
}
}
@ -370,7 +377,12 @@ public class TradeManager {
takeOfferResultHandler) {
disposeCheckOfferAvailabilityRequest(offer);
if (offer.getState() == Offer.State.AVAILABLE) {
TakerAsSellerTrade takerTrade = new TakerAsSellerTrade(offer, amount, model.getPeer(), pendingTradesStorage);
TakerTrade takerTrade;
if (offer.getDirection() == Offer.Direction.BUY)
takerTrade = new TakerAsSellerTrade(offer, amount, model.getPeer(), pendingTradesStorage);
else
takerTrade = new TakerAsBuyerTrade(offer, amount, model.getPeer(), pendingTradesStorage);
initTrade(takerTrade);
pendingTrades.add(takerTrade);
takerTrade.takeAvailableOffer();
@ -390,7 +402,7 @@ public class TradeManager {
// TODO handle overpaid securityDeposit
Coin amountToWithdraw = trade.getSecurityDeposit();
assert trade.getTradeAmount() != null;
if (trade instanceof OffererAsBuyerTrade)
if (trade instanceof OffererAsBuyerTrade || trade instanceof TakerAsBuyerTrade)
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@ -399,9 +411,13 @@ public class TradeManager {
if (transaction != null) {
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
if (trade instanceof OffererAsBuyerTrade)
((OffererAsBuyerTrade) trade).setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.COMPLETED);
else
((TakerAsSellerTrade) trade).setLifeCycleState(TakerAsSellerTrade.LifeCycleState.COMPLETED);
trade.setLifeCycleState(OffererAsBuyerTrade.LifeCycleState.COMPLETED);
else if (trade instanceof TakerAsSellerTrade)
trade.setLifeCycleState(TakerAsSellerTrade.LifeCycleState.COMPLETED);
else if (trade instanceof OffererAsSellerTrade)
trade.setLifeCycleState(OffererAsSellerTrade.LifeCycleState.COMPLETED);
else if (trade instanceof TakerAsBuyerTrade)
trade.setLifeCycleState(TakerAsBuyerTrade.LifeCycleState.COMPLETED);
pendingTrades.remove(trade);
closedTrades.add(trade);
@ -440,7 +456,7 @@ public class TradeManager {
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public ObservableList<OffererAsBuyerTrade> getOpenOfferTrades() {
public ObservableList<OffererTrade> getOpenOfferTrades() {
return openOfferTrades.getObservableList();
}

View File

@ -31,19 +31,19 @@ public class FiatTransferStartedMessage extends TradeMessage implements MailboxM
private static final long serialVersionUID = 1L;
public final byte[] buyerSignature;
public final Coin offererPayoutAmount;
public final Coin takerPayoutAmount;
public final Coin buyerPayoutAmount;
public final Coin sellerPayoutAmount;
public final String buyerPayoutAddress;
public FiatTransferStartedMessage(String tradeId,
byte[] buyerSignature,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
Coin buyerPayoutAmount,
Coin sellerPayoutAmount,
String buyerPayoutAddress) {
super(tradeId);
this.buyerSignature = buyerSignature;
this.offererPayoutAmount = offererPayoutAmount;
this.takerPayoutAmount = takerPayoutAmount;
this.buyerPayoutAmount = buyerPayoutAmount;
this.sellerPayoutAmount = sellerPayoutAmount;
this.buyerPayoutAddress = buyerPayoutAddress;
}
}

View File

@ -0,0 +1,60 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.messages;
import io.bitsquare.fiat.FiatAccount;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionOutput;
import java.io.Serializable;
import java.security.PublicKey;
import java.util.List;
import javax.annotation.concurrent.Immutable;
@Immutable
public class RequestPayDepositFromOffererMessage extends RequestPayDepositMessage implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = 1L;
public final Coin tradeAmount;
public RequestPayDepositFromOffererMessage(String tradeId,
Coin tradeAmount,
List<TransactionOutput> buyerConnectedOutputsForAllInputs,
List<TransactionOutput> buyerOutputs,
byte[] buyerTradeWalletPubKey,
PublicKey buyerP2PSigPublicKey,
PublicKey buyerP2PEncryptPublicKey,
FiatAccount buyerFiatAccount,
String buyerAccountId) {
super(tradeId,
buyerConnectedOutputsForAllInputs,
buyerOutputs,
buyerTradeWalletPubKey,
buyerP2PSigPublicKey,
buyerP2PEncryptPublicKey,
buyerFiatAccount,
buyerAccountId);
this.tradeAmount = tradeAmount;
}
}

View File

@ -0,0 +1,63 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.messages;
import io.bitsquare.fiat.FiatAccount;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import java.io.Serializable;
import java.security.PublicKey;
import java.util.List;
import javax.annotation.concurrent.Immutable;
@Immutable
public class RequestPublishDepositTxFromTakerMessage extends RequestPublishDepositTxMessage implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = 1L;
public byte[] sellerTradeWalletPubKey;
public RequestPublishDepositTxFromTakerMessage(String tradeId,
FiatAccount takerFiatAccount,
String takerAccountId,
byte[] sellerTradeWalletPubKey,
PublicKey takerP2PSigPublicKey,
PublicKey takerP2PEncryptPublicKey,
String takerContractAsJson,
String takerContractSignature,
String takerPayoutAddressString,
Transaction takersPreparedDepositTx,
List<TransactionOutput> takerConnectedOutputsForAllInputs) {
super(tradeId,
takerFiatAccount,
takerAccountId,
takerP2PSigPublicKey,
takerP2PEncryptPublicKey,
takerContractAsJson,
takerContractSignature,
takerPayoutAddressString,
takersPreparedDepositTx,
takerConnectedOutputsForAllInputs);
this.sellerTradeWalletPubKey = sellerTradeWalletPubKey;
}
}

View File

@ -37,12 +37,12 @@ import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignsCon
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererCreatesAndSignsDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestPayDepositMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererProcessRequestPayDepositFromOffererMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSendsRequestPublishDepositTxFromTakerMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.OffererSignsAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -134,19 +134,21 @@ public class OffererAsSellerProtocol implements Protocol {
// Trade
///////////////////////////////////////////////////////////////////////////////////////////
private void handle(RequestPayDepositMessage tradeMessage) {
private void handle(RequestPayDepositMessage tradeMessage, Peer sender) {
offererTradeProcessModel.setTradeMessage(tradeMessage);
offererAsSellerTrade.setTradingPeer(sender);
TaskRunner<OffererAsSellerTrade> taskRunner = new TaskRunner<>(offererAsSellerTrade,
() -> log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
OffererProcessRequestPayDepositMessage.class,
OffererProcessRequestPayDepositFromOffererMessage.class,
VerifyTakerAccount.class,
OffererCreatesAndSignsContract.class,
OffererCreatesAndSignsDepositTx.class,
OffererSendsRequestPublishDepositTxMessage.class
OffererSendsRequestPublishDepositTxFromTakerMessage.class
);
taskRunner.run();
}
@ -195,7 +197,7 @@ public class OffererAsSellerProtocol implements Protocol {
this::handleTaskRunnerFault);
taskRunner.addTasks(
VerifyOfferFeePayment.class,
VerifyTakeOfferFeePayment.class,
OffererSignsAndPublishPayoutTx.class,
OffererSendsPayoutTxPublishedMessage.class
);
@ -217,7 +219,7 @@ public class OffererAsSellerProtocol implements Protocol {
handle((RequestIsOfferAvailableMessage) tradeMessage, sender);
}
else if (tradeMessage instanceof RequestPayDepositMessage) {
handle((RequestPayDepositMessage) tradeMessage);
handle((RequestPayDepositMessage) tradeMessage, sender);
}
else if (tradeMessage instanceof DepositTxPublishedMessage) {
handle((DepositTxPublishedMessage) tradeMessage);

View File

@ -57,7 +57,7 @@ public class Offerer implements Serializable {
private List<TransactionOutput> connectedOutputsForAllInputs;
private List<TransactionOutput> outputs; // used to verify amounts with change outputs
private Transaction preparedDepositTx;
private PublicKey p2pSigPublicKey;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
@ -169,14 +169,6 @@ public class Offerer implements Serializable {
this.preparedDepositTx = preparedDepositTx;
}
public PublicKey getP2pSigPublicKey() {
return p2pSigPublicKey;
}
public void setP2pSigPublicKey(PublicKey p2pSigPublicKey) {
this.p2pSigPublicKey = p2pSigPublicKey;
}
@Override
public String toString() {
return "Offerer{" +

View File

@ -183,7 +183,7 @@ public class Taker implements Serializable {
return "Taker{" +
"accountId='" + accountId + '\'' +
", fiatAccount=" + fiatAccount +
", p2pSigPublicKey=" + p2pSigPubKey +
", p2pSigPubKey=" + p2pSigPubKey +
", p2pEncryptPubKey=" + p2pEncryptPubKey +
", contractAsJson='" + contractAsJson + '\'' +
", contractSignature='" + contractSignature + '\'' +

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class OffererCommitDepositTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCommitDepositTx.class);
public OffererCommitDepositTx(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererCommitDepositTx(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class OffererCommitsPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCommitsPayoutTx.class);
public OffererCommitsPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererCommitsPayoutTx(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -18,7 +18,6 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.OffererTrade;
import org.bitcoinj.core.Coin;
@ -29,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class OffererCreatesAndSignPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignPayoutTx.class);
public OffererCreatesAndSignPayoutTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererCreatesAndSignPayoutTx(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
@ -38,15 +37,9 @@ public class OffererCreatesAndSignPayoutTx extends OffererTradeTask {
try {
assert offererTrade.getTradeAmount() != null;
Coin securityDeposit = offererTrade.getSecurityDeposit();
Coin offererPayoutAmount = securityDeposit;
if (offererTrade.getOffer().getDirection() == Offer.Direction.BUY)
offererPayoutAmount = offererPayoutAmount.add(offererTrade.getTradeAmount());
Coin offererPayoutAmount = securityDeposit.add(offererTrade.getTradeAmount());
Coin takerPayoutAmount = securityDeposit;
if (offererTrade.getOffer().getDirection() == Offer.Direction.SELL)
takerPayoutAmount = takerPayoutAmount.add(offererTrade.getTradeAmount());
byte[] offererPayoutTxSignature = offererTradeProcessModel.getTradeWalletService().createAndSignPayoutTx(
offererTrade.getDepositTx(),
offererPayoutAmount,

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class OffererCreatesAndSignsContract extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsContract.class);
public OffererCreatesAndSignsContract(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererCreatesAndSignsContract(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -30,19 +30,19 @@ import org.slf4j.LoggerFactory;
public class OffererCreatesAndSignsDepositTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsDepositTx.class);
public OffererCreatesAndSignsDepositTx(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererCreatesAndSignsDepositTx(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
protected void doRun() {
try {
assert offererTrade.getTradeAmount() != null;
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE).add(offererTrade.getTradeAmount());
Coin msOutputAmount = offererInputAmount.add(offererTrade.getSecurityDeposit());
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().takerCreatesAndSignsDepositTx(
offererInputAmount,
Coin inputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE).add(offererTrade.getTradeAmount());
Coin msOutputAmount = inputAmount.add(offererTrade.getSecurityDeposit());
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createAndSignDepositTx(
inputAmount,
msOutputAmount,
offererTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.taker.getOutputs(),

View File

@ -32,8 +32,8 @@ import org.slf4j.LoggerFactory;
public class OffererCreatesDepositTxInputs extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesDepositTxInputs.class);
public OffererCreatesDepositTxInputs(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererCreatesDepositTxInputs(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
@ -41,7 +41,7 @@ public class OffererCreatesDepositTxInputs extends OffererTradeTask {
try {
log.debug("offererTrade.id" + offererTrade.getId());
Coin inputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(inputAmount,
TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createDepositTxInputs(inputAmount,
offererTradeProcessModel.offerer.getAddressEntry());
offererTradeProcessModel.offerer.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.checkTradeId;
public class OffererProcessDepositTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessDepositTxPublishedMessage.class);
public OffererProcessDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererProcessDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.*;
public class OffererProcessFiatTransferStartedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessFiatTransferStartedMessage.class);
public OffererProcessFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererProcessFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
@ -44,8 +44,8 @@ public class OffererProcessFiatTransferStartedMessage extends OffererTradeTask {
checkNotNull(message);
offererTradeProcessModel.taker.setSignature(checkNotNull(message.buyerSignature));
offererTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
offererTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
offererTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.sellerPayoutAmount)));
offererTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.buyerPayoutAmount)));
offererTradeProcessModel.taker.setPayoutAddressString(nonEmptyStringOf(message.buyerPayoutAddress));
if (offererTrade instanceof OffererAsBuyerTrade)

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.checkTradeId;
public class OffererProcessPayoutTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessPayoutTxPublishedMessage.class);
public OffererProcessPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererProcessPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.*;
public class OffererProcessRequestDepositTxInputsMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestDepositTxInputsMessage.class);
public OffererProcessRequestDepositTxInputsMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererProcessRequestDepositTxInputsMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositFromOffererMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -27,17 +27,17 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class OffererProcessRequestPayDepositMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestPayDepositMessage.class);
public class OffererProcessRequestPayDepositFromOffererMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestPayDepositFromOffererMessage.class);
public OffererProcessRequestPayDepositMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererProcessRequestPayDepositFromOffererMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
protected void doRun() {
try {
RequestPayDepositMessage message = (RequestPayDepositMessage) offererTradeProcessModel.getTradeMessage();
RequestPayDepositFromOffererMessage message = (RequestPayDepositFromOffererMessage) offererTradeProcessModel.getTradeMessage();
checkTradeId(offererTradeProcessModel.getId(), message);
checkNotNull(message);
@ -49,6 +49,7 @@ public class OffererProcessRequestPayDepositMessage extends OffererTradeTask {
offererTradeProcessModel.taker.setP2pEncryptPubKey(checkNotNull(message.buyerP2PEncryptPublicKey));
offererTradeProcessModel.taker.setFiatAccount(checkNotNull(message.buyerFiatAccount));
offererTradeProcessModel.taker.setAccountId(nonEmptyStringOf(message.buyerAccountId));
offererTrade.setTradeAmount(positiveCoinOf(nonZeroCoinOf(message.tradeAmount)));
complete();
} catch (Throwable t) {

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.*;
public class OffererProcessRequestPublishDepositTxMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererProcessRequestPublishDepositTxMessage.class);
public OffererProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class OffererSendsDepositTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsDepositTxPublishedMessage.class);
public OffererSendsDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererSendsDepositTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class OffererSendsFiatTransferStartedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsFiatTransferStartedMessage.class);
public OffererSendsFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererSendsFiatTransferStartedMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class OffererSendsPayoutTxPublishedMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsPayoutTxPublishedMessage.class);
public OffererSendsPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererSendsPayoutTxPublishedMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
@ -40,7 +40,7 @@ public class OffererSendsPayoutTxPublishedMessage extends OffererTradeTask {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(offererTradeProcessModel.getId(), offererTradeProcessModel.getPayoutTx());
offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(),
tradeMessage,
offererTradeProcessModel.offerer.getP2pSigPublicKey(),
offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.offerer.getP2pEncryptPubKey(),
new SendMessageListener() {
@Override

View File

@ -22,25 +22,26 @@ import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererAsBuyerTrade;
import io.bitsquare.trade.OffererAsSellerTrade;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxFromTakerMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererSendsRequestPublishDepositTxMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsRequestPublishDepositTxMessage.class);
public class OffererSendsRequestPublishDepositTxFromTakerMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsRequestPublishDepositTxFromTakerMessage.class);
public OffererSendsRequestPublishDepositTxMessage(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererSendsRequestPublishDepositTxFromTakerMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
protected void doRun() {
try {
RequestPublishDepositTxMessage tradeMessage = new RequestPublishDepositTxMessage(
RequestPublishDepositTxFromTakerMessage tradeMessage = new RequestPublishDepositTxFromTakerMessage(
offererTradeProcessModel.getId(),
offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.offerer.getAccountId(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.offerer.getP2pEncryptPublicKey(),
offererTrade.getContractAsJson(),

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class OffererSendsRequestSellerDepositPaymentMessage extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSendsRequestSellerDepositPaymentMessage.class);
public OffererSendsRequestSellerDepositPaymentMessage(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererSendsRequestSellerDepositPaymentMessage(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -36,8 +36,8 @@ import org.slf4j.LoggerFactory;
public class OffererSignsAndPublishDepositTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSignsAndPublishDepositTx.class);
public OffererSignsAndPublishDepositTx(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererSignsAndPublishDepositTx(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -34,8 +34,8 @@ import org.slf4j.LoggerFactory;
public class OffererSignsAndPublishPayoutTx extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererSignsAndPublishPayoutTx.class);
public OffererSignsAndPublishPayoutTx(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
public OffererSignsAndPublishPayoutTx(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override
@ -44,12 +44,12 @@ public class OffererSignsAndPublishPayoutTx extends OffererTradeTask {
offererTradeProcessModel.getTradeWalletService().signAndPublishPayoutTx(
offererTrade.getDepositTx(),
offererTradeProcessModel.taker.getSignature(),
offererTradeProcessModel.offerer.getPayoutAmount(),
offererTradeProcessModel.taker.getPayoutAmount(),
offererTradeProcessModel.offerer.getPayoutAmount(),
offererTradeProcessModel.taker.getPayoutAddressString(),
offererTradeProcessModel.offerer.getAddressEntry(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.taker.getTradeWalletPubKey(),
offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() {
@Override

View File

@ -17,9 +17,6 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.exceptions.SigningException;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
@ -33,10 +30,10 @@ class OffererTradeTask extends Task<OffererTrade> {
protected final OffererProcessModel offererTradeProcessModel;
protected final OffererTrade offererTrade;
OffererTradeTask(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model);
OffererTradeTask(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
offererTrade = model;
this.offererTrade = offererTrade;
offererTradeProcessModel = offererTrade.getProcessModel();
}

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class OffererVerifiesAndSignsContract extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererVerifiesAndSignsContract.class);
public OffererVerifiesAndSignsContract(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public OffererVerifiesAndSignsContract(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -26,8 +26,8 @@ import org.slf4j.LoggerFactory;
public class VerifyTakeOfferFeePayment extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyTakeOfferFeePayment.class);
public VerifyTakeOfferFeePayment(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public VerifyTakeOfferFeePayment(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class VerifyTakerAccount extends OffererTradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class);
public VerifyTakerAccount(TaskRunner taskHandler, OffererTrade offererTradeProcessModel) {
super(taskHandler, offererTradeProcessModel);
public VerifyTakerAccount(TaskRunner taskHandler, OffererTrade offererTrade) {
super(taskHandler, offererTrade);
}
@Override

View File

@ -34,7 +34,7 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitsPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesAndSignsPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCreatesDepositTxInputs;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessPayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessRequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerProcessRequestPublishDepositTxFromTakerMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsDepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsFiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerSendsRequestPayDepositMessage;
@ -119,7 +119,7 @@ public class TakerAsBuyerProtocol implements Protocol {
() -> log.debug("taskRunner at handleRequestPublishDepositTxMessage completed"),
this::handleTaskRunnerFault);
taskRunner.addTasks(
TakerProcessRequestPublishDepositTxMessage.class,
TakerProcessRequestPublishDepositTxFromTakerMessage.class,
VerifyOffererAccount.class,
TakerVerifiesAndSignsContract.class,
TakerSignsAndPublishDepositTx.class,

View File

@ -55,7 +55,6 @@ public class Offerer implements Serializable {
private byte[] signature;
private FiatAccount fiatAccount;
private String accountId;
private PublicKey p2pSigPublicKey;
private PublicKey p2pEncryptPubKey;
private String contractAsJson;
private String contractSignature;
@ -153,15 +152,6 @@ public class Offerer implements Serializable {
this.accountId = accountId;
}
@Nullable
public PublicKey getP2pSigPublicKey() {
return p2pSigPublicKey;
}
public void setP2pSigPublicKey(PublicKey p2pSigPublicKey) {
this.p2pSigPublicKey = p2pSigPublicKey;
}
@Nullable
public PublicKey getP2pEncryptPubKey() {
return p2pEncryptPubKey;
@ -218,7 +208,7 @@ public class Offerer implements Serializable {
", signature=" + Arrays.toString(signature) +
", fiatAccount=" + fiatAccount +
", accountId='" + accountId + '\'' +
", p2pSigPublicKey=" + p2pSigPublicKey +
", p2pSigPubKey=" + p2pSigPubKey +
", p2pEncryptPubKey=" + p2pEncryptPubKey +
'}';
}

View File

@ -58,6 +58,7 @@ public class Taker implements Serializable {
private Transaction preparedDepositTx;
private List<TransactionOutput> outputs; // used to verify amounts with change outputs
private byte[] payoutTxSignature;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization

View File

@ -34,8 +34,8 @@ import org.slf4j.LoggerFactory;
public class BroadcastTakeOfferFeeTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(BroadcastTakeOfferFeeTx.class);
public BroadcastTakeOfferFeeTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public BroadcastTakeOfferFeeTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class CreateTakeOfferFeeTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateTakeOfferFeeTx.class);
public CreateTakeOfferFeeTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public CreateTakeOfferFeeTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class TakerCommitDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCommitDepositTx.class);
public TakerCommitDepositTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerCommitDepositTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class TakerCommitsPayoutTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCommitsPayoutTx.class);
public TakerCommitsPayoutTx(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerCommitsPayoutTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class TakerCreatesAndSignContract extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignContract.class);
public TakerCreatesAndSignContract(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerCreatesAndSignContract(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -30,19 +30,19 @@ import org.slf4j.LoggerFactory;
public class TakerCreatesAndSignsDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignsDepositTx.class);
public TakerCreatesAndSignsDepositTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerCreatesAndSignsDepositTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
protected void doRun() {
try {
assert takerTrade.getTradeAmount() != null;
Coin takerInputAmount = takerTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
Coin msOutputAmount = takerInputAmount.add(takerTrade.getSecurityDeposit());
TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().takerCreatesAndSignsDepositTx(
takerInputAmount,
Coin inputAmount = takerTrade.getSecurityDeposit().add(FeePolicy.TX_FEE).add(takerTrade.getTradeAmount());
Coin msOutputAmount = inputAmount.add(takerTrade.getSecurityDeposit());
TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().createAndSignDepositTx(
inputAmount,
msOutputAmount,
takerTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.offerer.getOutputs(),
@ -51,7 +51,6 @@ public class TakerCreatesAndSignsDepositTx extends TakerTradeTask {
takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.getArbitratorPubKey());
takerTradeProcessModel.taker.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
takerTradeProcessModel.taker.setPreparedDepositTx(result.getDepositTx());

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class TakerCreatesAndSignsPayoutTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesAndSignsPayoutTx.class);
public TakerCreatesAndSignsPayoutTx(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerCreatesAndSignsPayoutTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
@ -40,15 +40,16 @@ public class TakerCreatesAndSignsPayoutTx extends TakerTradeTask {
Coin offererPayoutAmount = securityDeposit;
Coin takerPayoutAmount = securityDeposit.add(takerTrade.getTradeAmount());
byte[] takerPayoutTxSignature = takerTradeProcessModel.getTradeWalletService().createAndSignPayoutTx(
takerTrade.getDepositTx(),
offererPayoutAmount,
takerPayoutAmount,
offererPayoutAmount,
takerTradeProcessModel.taker.getAddressEntry(),
takerTradeProcessModel.offerer.getPayoutAddressString(),
takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.getArbitratorPubKey());
takerTradeProcessModel.taker.setPayoutTxSignature(takerPayoutTxSignature);

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class TakerCreatesDepositTxInputs extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerCreatesDepositTxInputs.class);
public TakerCreatesDepositTxInputs(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerCreatesDepositTxInputs(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
@ -39,7 +39,7 @@ public class TakerCreatesDepositTxInputs extends TakerTradeTask {
try {
log.debug("takerTrade.id" + takerTrade.getId());
Coin inputAmount = takerTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(inputAmount,
TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().createDepositTxInputs(inputAmount,
takerTradeProcessModel.taker.getAddressEntry());
takerTradeProcessModel.taker.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.checkTradeId;
public class TakerProcessDepositTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessDepositTxPublishedMessage.class);
public TakerProcessDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerProcessDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.*;
public class TakerProcessFiatTransferStartedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessFiatTransferStartedMessage.class);
public TakerProcessFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerProcessFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
@ -44,8 +44,8 @@ public class TakerProcessFiatTransferStartedMessage extends TakerTradeTask {
checkNotNull(message);
takerTradeProcessModel.offerer.setSignature(checkNotNull(message.buyerSignature));
takerTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
takerTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount)));
takerTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.buyerPayoutAmount)));
takerTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.sellerPayoutAmount)));
takerTradeProcessModel.offerer.setPayoutAddressString(nonEmptyStringOf(message.buyerPayoutAddress));
if (takerTrade instanceof TakerAsBuyerTrade)

View File

@ -32,8 +32,8 @@ import static io.bitsquare.util.Validator.checkTradeId;
public class TakerProcessPayoutTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessPayoutTxPublishedMessage.class);
public TakerProcessPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerProcessPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxFromTakerMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -27,23 +27,25 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*;
public class TakerProcessRequestPublishDepositTxMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessRequestPublishDepositTxMessage.class);
public class TakerProcessRequestPublishDepositTxFromTakerMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessRequestPublishDepositTxFromTakerMessage.class);
public TakerProcessRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerProcessRequestPublishDepositTxFromTakerMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
protected void doRun() {
try {
RequestPublishDepositTxMessage message = (RequestPublishDepositTxMessage) takerTradeProcessModel.getTradeMessage();
RequestPublishDepositTxFromTakerMessage message = (RequestPublishDepositTxFromTakerMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.takerFiatAccount));
takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.takerAccountId));
takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.takerP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pSigPubKey(checkNotNull(message.takerP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pSigPubKey(checkNotNull(message.takerP2PSigPublicKey));
takerTradeProcessModel.offerer.setTradeWalletPubKey(checkNotNull(message.sellerTradeWalletPubKey));
takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.takerP2PEncryptPublicKey));
takerTradeProcessModel.offerer.setContractAsJson(nonEmptyStringOf(message.takerContractAsJson));
takerTradeProcessModel.offerer.setContractSignature(nonEmptyStringOf(message.takerContractSignature));

View File

@ -30,8 +30,8 @@ import static io.bitsquare.util.Validator.*;
public class TakerProcessRequestSellerDepositPaymentMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerProcessRequestSellerDepositPaymentMessage.class);
public TakerProcessRequestSellerDepositPaymentMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerProcessRequestSellerDepositPaymentMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
@ -45,7 +45,7 @@ public class TakerProcessRequestSellerDepositPaymentMessage extends TakerTradeTa
checkArgument(message.buyerConnectedOutputsForAllInputs.size() > 0);
takerTradeProcessModel.offerer.setOutputs(checkNotNull(message.buyerOutputs));
takerTradeProcessModel.offerer.setTradeWalletPubKey(checkNotNull(message.buyerTradeWalletPubKey));
takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.buyerP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pSigPubKey(checkNotNull(message.buyerP2PSigPublicKey));
takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.buyerP2PEncryptPublicKey));
takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.buyerFiatAccount));
takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.buyerAccountId));

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class TakerSendsDepositTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsDepositTxPublishedMessage.class);
public TakerSendsDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerSendsDepositTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class TakerSendsFiatTransferStartedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsFiatTransferStartedMessage.class);
public TakerSendsFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerSendsFiatTransferStartedMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
@ -39,8 +39,8 @@ public class TakerSendsFiatTransferStartedMessage extends TakerTradeTask {
try {
FiatTransferStartedMessage tradeMessage = new FiatTransferStartedMessage(takerTradeProcessModel.getId(),
takerTradeProcessModel.taker.getPayoutTxSignature(),
takerTradeProcessModel.offerer.getPayoutAmount(),
takerTradeProcessModel.taker.getPayoutAmount(),
takerTradeProcessModel.offerer.getPayoutAmount(),
takerTradeProcessModel.taker.getAddressEntry().getAddressString());
takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), tradeMessage,

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class TakerSendsPayoutTxPublishedMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsPayoutTxPublishedMessage.class);
public TakerSendsPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerSendsPayoutTxPublishedMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
@ -40,7 +40,7 @@ public class TakerSendsPayoutTxPublishedMessage extends TakerTradeTask {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(takerTradeProcessModel.getId(), takerTradeProcessModel.getPayoutTx());
takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(),
tradeMessage,
takerTradeProcessModel.offerer.getP2pSigPublicKey(),
takerTradeProcessModel.offerer.getP2pSigPubKey(),
takerTradeProcessModel.offerer.getP2pEncryptPubKey(),
new SendMessageListener() {
@Override

View File

@ -32,8 +32,8 @@ import org.slf4j.LoggerFactory;
public class TakerSendsRequestDepositTxInputsMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestDepositTxInputsMessage.class);
public TakerSendsRequestDepositTxInputsMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerSendsRequestDepositTxInputsMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
private int retryCounter = 0;

View File

@ -22,7 +22,7 @@ import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerAsBuyerTrade;
import io.bitsquare.trade.TakerAsSellerTrade;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositFromOffererMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -30,15 +30,16 @@ import org.slf4j.LoggerFactory;
public class TakerSendsRequestPayDepositMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestPayDepositMessage.class);
public TakerSendsRequestPayDepositMessage(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerSendsRequestPayDepositMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
protected void doRun() {
try {
RequestPayDepositMessage tradeMessage = new RequestPayDepositMessage(
RequestPayDepositFromOffererMessage message = new RequestPayDepositFromOffererMessage(
takerTradeProcessModel.getId(),
model.getTradeAmount(),
takerTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.taker.getOutputs(),
takerTradeProcessModel.taker.getTradeWalletPubKey(),
@ -47,7 +48,7 @@ public class TakerSendsRequestPayDepositMessage extends TakerTradeTask {
takerTradeProcessModel.taker.getFiatAccount(),
takerTradeProcessModel.taker.getAccountId());
takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), message, new SendMessageListener() {
@Override
public void handleResult() {
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");

View File

@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
public class TakerSendsRequestPublishDepositTxMessage extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSendsRequestPublishDepositTxMessage.class);
public TakerSendsRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerSendsRequestPublishDepositTxMessage(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -36,23 +36,23 @@ import org.slf4j.LoggerFactory;
public class TakerSignsAndPublishDepositTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSignsAndPublishDepositTx.class);
public TakerSignsAndPublishDepositTx(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerSignsAndPublishDepositTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override
protected void doRun() {
try {
Coin inputAmount = takerTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
takerTradeProcessModel.getTradeWalletService().signAndPublishDepositTx(
takerTradeProcessModel.offerer.getPreparedDepositTx(),
takerTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.taker.getOutputs(),
inputAmount,
takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() {
@Override

View File

@ -34,8 +34,8 @@ import org.slf4j.LoggerFactory;
public class TakerSignsAndPublishPayoutTx extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerSignsAndPublishPayoutTx.class);
public TakerSignsAndPublishPayoutTx(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public TakerSignsAndPublishPayoutTx(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -30,10 +30,10 @@ class TakerTradeTask extends Task<TakerTrade> {
protected final TakerProcessModel takerTradeProcessModel;
protected final TakerTrade takerTrade;
TakerTradeTask(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
TakerTradeTask(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
takerTrade = model;
this.takerTrade = takerTrade;
takerTradeProcessModel = takerTrade.getProcessModel();
}

View File

@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
public class TakerVerifiesAndSignsContract extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(TakerVerifiesAndSignsContract.class);
public TakerVerifiesAndSignsContract(TaskRunner taskHandler, TakerTrade takerTradeProcessModel) {
super(taskHandler, takerTradeProcessModel);
public TakerVerifiesAndSignsContract(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -26,8 +26,8 @@ import org.slf4j.LoggerFactory;
public class VerifyOfferFeePayment extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyOfferFeePayment.class);
public VerifyOfferFeePayment(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public VerifyOfferFeePayment(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override

View File

@ -26,8 +26,8 @@ import org.slf4j.LoggerFactory;
public class VerifyOffererAccount extends TakerTradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
public VerifyOffererAccount(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model);
public VerifyOffererAccount(TaskRunner taskHandler, TakerTrade takerTrade) {
super(taskHandler, takerTrade);
}
@Override