Transaction handling on wallet service side cleaned up

This commit is contained in:
Manfred Karrer 2015-03-16 22:34:17 +01:00
parent 3db41e4edf
commit 5645f7618e
33 changed files with 202 additions and 234 deletions

@ -78,8 +78,6 @@ import javax.annotation.concurrent.GuardedBy;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
@ -305,7 +303,7 @@ public class WalletService {
return arbitratorDepositAddressEntry;
}
public AddressEntry getAddressInfo(String offerId) {
public AddressEntry getAddressEntry(String offerId) {
Optional<AddressEntry> addressEntry = getAddressEntryList().stream().filter(e ->
offerId.equals(e.getOfferId())).findFirst();
@ -525,7 +523,7 @@ public class WalletService {
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)
AddressEntry addressEntry = getAddressInfo(offerId);
AddressEntry addressEntry = getAddressEntry(offerId);
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry, true);
sendRequest.changeAddress = addressEntry.getAddress();
wallet.completeTx(sendRequest);
@ -549,8 +547,8 @@ public class WalletService {
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, getAddressInfo(offerId), true);
sendRequest.changeAddress = getAddressInfo(offerId).getAddress();
sendRequest.coinSelector = new AddressBasedCoinSelector(params, getAddressEntry(offerId), true);
sendRequest.changeAddress = getAddressEntry(offerId).getAddress();
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, callback);
@ -597,7 +595,6 @@ public class WalletService {
// Trade process
///////////////////////////////////////////////////////////////////////////////////////////
// 1. step: Define offerers inputs and outputs for the deposit tx
public TransactionDataResult offererCreatesDepositTxInputs(Coin inputAmount, AddressEntry addressInfo) throws InsufficientMoneyException,
TransactionVerificationException, WalletException {
@ -654,7 +651,6 @@ public class WalletService {
return new TransactionDataResult(connectedOutputsForAllInputs, outputs);
}
// 2. step: Taker creates a deposit tx and signs his inputs
public TransactionDataResult takerCreatesAndSignsDepositTx(Coin takerInputAmount,
Coin msOutputAmount,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
@ -753,17 +749,15 @@ public class WalletService {
return new TransactionDataResult(depositTx, connectedOutputsForAllTakerInputs, takerOutputs);
}
// 3. step: deposit tx
// Offerer signs tx and publishes it
public void offererSignAndPublishTx(Transaction takersDepositTx,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> takerConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs,
Coin offererInputAmount,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException, WalletException {
public void offererSignsAndPublishTx(Transaction takersDepositTx,
List<TransactionOutput> offererConnectedOutputsForAllInputs,
List<TransactionOutput> takerConnectedOutputsForAllInputs,
List<TransactionOutput> offererOutputs,
Coin offererInputAmount,
byte[] offererPubKey,
byte[] takerPubKey,
byte[] arbitratorPubKey,
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException, WalletException {
checkArgument(offererConnectedOutputsForAllInputs.size() > 0);
checkArgument(takerConnectedOutputsForAllInputs.size() > 0);
@ -832,21 +826,10 @@ public class WalletService {
Futures.addCallback(broadcastComplete, callback);
}
// 4 step deposit tx: Offerer send deposit tx to taker
public Transaction takerCommitDepositTx(Transaction depositTx) throws WalletException {
log.trace("takerCommitDepositTx");
log.trace("inputs: ");
log.trace("depositTx=" + depositTx);
// If not recreate the tx we get a null pointer at receivePending
log.debug("tx id " + depositTx.getHashAsString());
public Transaction takerCommitsDepositTx(Transaction depositTx) throws WalletException {
// We need to recreate the tx we get a null pointer otherwise
depositTx = new Transaction(params, depositTx.bitcoinSerialize());
log.debug("tx id " + depositTx.getHashAsString());
log.trace("depositTx=" + depositTx);
// boolean isAlreadyInWallet = wallet.maybeCommitTx(depositTx);
//log.trace("isAlreadyInWallet=" + isAlreadyInWallet);
// Manually add the multisigContract to the wallet, overriding the isRelevant checks so we can track
// it and check for double-spends later
try {
wallet.receivePending(depositTx, null, true);
} catch (Throwable t) {
@ -856,94 +839,59 @@ public class WalletService {
}
return depositTx;
}
// 5. step payout tx: Offerer creates payout tx and signs it
public Pair<ECKey.ECDSASignature, Transaction> offererCreatesAndSignsPayoutTx(String depositTxID,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
String takerAddress,
String tradeID) throws AddressFormatException {
log.debug("offererCreatesAndSignsPayoutTx");
log.trace("inputs: ");
log.trace("depositTxID=" + depositTxID);
log.trace("offererPaybackAmount=" + offererPaybackAmount.toFriendlyString());
log.trace("takerPaybackAmount=" + takerPaybackAmount.toFriendlyString());
log.trace("takerAddress=" + takerAddress);
// Offerer has published depositTx earlier, so he has it in his wallet
Transaction depositTx = wallet.getTransaction(new Sha256Hash(depositTxID));
// String depositTxAsHex = Utils.HEX.encode(depositTx.bitcoinSerialize());
public TransactionDataResult offererCreatesAndSignsPayoutTx(Transaction depositTx,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
String takerAddressString,
AddressEntry addressEntry) throws AddressFormatException, TransactionVerificationException {
// We create the payout tx
Transaction tx = createPayoutTx(depositTx, offererPaybackAmount, takerPaybackAmount,
getAddressInfo(tradeID).getAddressString(), takerAddress);
Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, addressEntry.getAddressString(), takerAddressString);
// We create the signature for that tx
TransactionOutput multiSigOutput = tx.getInput(0).getConnectedOutput();
TransactionOutput multiSigOutput = payoutTx.getInput(0).getConnectedOutput();
Script multiSigScript = multiSigOutput.getScriptPubKey();
Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = getAddressInfo(tradeID).getKeyPair().sign(sigHash);
Sha256Hash sigHash = payoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature offererSignature = addressEntry.getKeyPair().sign(sigHash);
TransactionSignature offererTxSig = new TransactionSignature(offererSignature, Transaction.SigHash.ALL, false);
Script inputScript = ScriptBuilder.createMultiSigInputScript(ImmutableList.of(offererTxSig));
tx.getInput(0).setScriptSig(inputScript);
verifyTransaction(payoutTx);
log.trace("sigHash=" + sigHash);
return new Pair<>(offererSignature, depositTx);
return new TransactionDataResult(payoutTx, offererSignature);
}
// 6. step payout tx: Taker signs and publish tx
public void takerSignsAndSendsTx(Transaction depositTx,
ECKey.ECDSASignature offererSignature,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
String offererAddress,
String tradeID,
FutureCallback<Transaction> callback) throws AddressFormatException {
log.debug("takerSignsAndSendsTx");
log.trace("inputs: ");
log.trace("depositTx=" + depositTx);
log.trace("offererSignature=" + offererSignature);
log.trace("offererPaybackAmount=" + offererPaybackAmount.toFriendlyString());
log.trace("takerPaybackAmount=" + takerPaybackAmount.toFriendlyString());
log.trace("offererAddress=" + offererAddress);
log.trace("callback=" + callback);
public void takerSignsAndPublishPayoutTx(Transaction depositTx,
ECKey.ECDSASignature offererSignature,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
String offererAddressString,
AddressEntry addressEntry,
FutureCallback<Transaction> callback) throws AddressFormatException, TransactionVerificationException,
WalletException {
// We create the payout tx
Transaction tx = createPayoutTx(depositTx, offererPaybackAmount, takerPaybackAmount, offererAddress, getAddressInfo(tradeID).getAddressString());
Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, offererAddressString, addressEntry.getAddressString());
// We sign that tx with our key and apply the signature form the offerer
TransactionOutput multiSigOutput = tx.getInput(0).getConnectedOutput();
// We sign that tx with our key and apply the signature from the offerer
TransactionInput input = payoutTx.getInput(0);
TransactionOutput multiSigOutput = input.getConnectedOutput();
Script multiSigScript = multiSigOutput.getScriptPubKey();
Sha256Hash sigHash = tx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
log.trace("sigHash=" + sigHash);
ECKey.ECDSASignature takerSignature = getAddressInfo(tradeID).getKeyPair().sign(sigHash);
Sha256Hash sigHash = payoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature takerSignature = addressEntry.getKeyPair().sign(sigHash);
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
TransactionSignature offererTxSig = new TransactionSignature(offererSignature, Transaction.SigHash.ALL, false);
Script inputScript = ScriptBuilder.createMultiSigInputScript(ImmutableList.of(offererTxSig, takerTxSig));
tx.getInput(0).setScriptSig(inputScript);
input.setScriptSig(inputScript);
log.trace("verify tx");
tx.verify();
verifyTransaction(payoutTx);
checkWalletConsistency();
checkScriptSig(payoutTx, input, 0);
input.verify(multiSigOutput);
log.trace("check if it can be correctly spent for ms input");
tx.getInput(0).getScriptSig().correctlySpends(tx, 0, multiSigScript);
log.trace("verify multiSigOutput");
tx.getInput(0).verify(multiSigOutput);
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx);
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(payoutTx);
Futures.addCallback(broadcastComplete, callback);
log.trace("getTransactions.size=" + wallet.getTransactions(true).size());
log.trace("Check if wallet is consistent: result=" + wallet.isConsistent());
printTxWithInputs("takerSignsAndSendsTx", tx);
log.debug("tx = " + tx);
printTxWithInputs("payoutTx", payoutTx);
}
@ -970,23 +918,14 @@ public class WalletService {
return ScriptBuilder.createMultiSigOutputScript(2, keys);
}
private Transaction createPayoutTx(Transaction depositTx, Coin offererPaybackAmount, Coin takerPaybackAmount,
String offererAddress, String takerAddress) throws AddressFormatException {
log.trace("createPayoutTx");
log.trace("inputs: ");
log.trace("depositTx=" + depositTx);
log.trace("offererPaybackAmount=" + offererPaybackAmount.toFriendlyString());
log.trace("takerPaybackAmount=" + takerPaybackAmount.toFriendlyString());
log.trace("offererAddress=" + offererAddress);
log.trace("takerAddress=" + takerAddress);
private Transaction createPayoutTx(Transaction depositTx, Coin offererPayoutAmount, Coin takerPayoutAmount,
String offererAddressString, String takerAddressString) throws AddressFormatException {
// Transaction depositTx = new Transaction(params, Utils.parseAsHexOrBase58(depositTx));
TransactionOutput multiSigOutput = depositTx.getOutput(0);
Transaction tx = new Transaction(params);
tx.addInput(multiSigOutput);
tx.addOutput(offererPaybackAmount, new Address(params, offererAddress));
tx.addOutput(takerPaybackAmount, new Address(params, takerAddress));
log.trace("tx=" + tx);
tx.addOutput(offererPayoutAmount, new Address(params, offererAddressString));
tx.addOutput(takerPayoutAmount, new Address(params, takerAddressString));
return tx;
}
@ -1085,12 +1024,15 @@ public class WalletService {
// Inner classes
///////////////////////////////////////////////////////////////////////////////////////////
public class TransactionDataResult {
private final List<TransactionOutput> connectedOutputsForAllInputs;
private final List<TransactionOutput> outputs;
private List<TransactionOutput> connectedOutputsForAllInputs;
private List<TransactionOutput> outputs;
private Transaction depositTx;
private Transaction payoutTx;
private ECKey.ECDSASignature offererSignature;
public TransactionDataResult(List<TransactionOutput> connectedOutputsForAllInputs, List<TransactionOutput> outputs) {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
this.outputs = outputs;
@ -1102,6 +1044,12 @@ public class WalletService {
this.outputs = outputs;
}
public TransactionDataResult(Transaction payoutTx, ECKey.ECDSASignature offererSignature) {
this.payoutTx = payoutTx;
this.offererSignature = offererSignature;
}
public List<TransactionOutput> getOutputs() {
return outputs;
}
@ -1113,6 +1061,14 @@ public class WalletService {
public Transaction getDepositTx() {
return depositTx;
}
public Transaction getPayoutTx() {
return payoutTx;
}
public ECKey.ECDSASignature getOffererSignature() {
return offererSignature;
}
}
private static class ObservableDownloadListener extends DownloadListener {

@ -184,7 +184,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
};
AddressEntry addressEntry = walletService.getAddressInfo(getTrade().getId());
AddressEntry addressEntry = walletService.getAddressEntry(getTrade().getId());
String fromAddress = addressEntry.getAddressString();
try {
walletService.sendFunds(fromAddress, toAddress, getAmountToWithdraw(), callback);
@ -258,7 +258,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
}
Coin getAmountToWithdraw() {
AddressEntry addressEntry = walletService.getAddressInfo(getTrade().getId());
AddressEntry addressEntry = walletService.getAddressEntry(getTrade().getId());
log.debug("trade id " + getTrade().getId());
log.debug("getAddressString " + addressEntry.getAddressString());
log.debug("funds " + walletService.getBalanceForAddress(addressEntry.getAddress()).subtract(FeePolicy

@ -125,7 +125,7 @@ class CreateOfferDataModel implements Activatable, DataModel {
networkFeeAsCoin.set(FeePolicy.TX_FEE);
if (walletService != null && walletService.getWallet() != null) {
addressEntry = walletService.getAddressInfo(offerId);
addressEntry = walletService.getAddressEntry(offerId);
walletService.addBalanceListener(new BalanceListener(getAddressEntry().getAddress()) {
@Override

@ -121,7 +121,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
calculateVolume();
calculateTotalToPay();
addressEntry = walletService.getAddressInfo(offer.getId());
addressEntry = walletService.getAddressEntry(offer.getId());
walletService.addBalanceListener(new BalanceListener(addressEntry.getAddress()) {
@Override
public void onBalanceChanged(@NotNull Coin balance) {

@ -48,7 +48,7 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
protected void doRun() {
Coin totalsNeeded = model.getOffer().getSecurityDeposit().add(FeePolicy.CREATE_OFFER_FEE).add(FeePolicy.TX_FEE);
AddressEntry addressEntry = model.getWalletService().getAddressInfo(model.getOffer().getId());
AddressEntry addressEntry = model.getWalletService().getAddressEntry(model.getOffer().getId());
Coin balance = model.getWalletService().getBalanceForAddress(addressEntry.getAddress());
if (balance.compareTo(totalsNeeded) >= 0) {

@ -44,15 +44,16 @@ public class OfferSharedModel extends SharedModel {
protected final BlockChainService blockChainService;
protected final SignatureService signatureService;
// derived
protected final String id;
protected final BankAccount bankAccount;
protected final String accountId;
protected final PublicKey networkPubKey;
protected final byte[] registrationPubKey;
protected final DeterministicKey registrationKeyPair;
protected final byte[] arbitratorPubKey;
protected final AddressEntry addressInfo;
protected final AddressEntry addressEntry;
// data written/read by tasks
protected TradeMessage tradeMessage;
@ -69,11 +70,12 @@ public class OfferSharedModel extends SharedModel {
this.blockChainService = blockChainService;
this.signatureService = signatureService;
id = offer.getId();
//TODO use default arbitrator for now
arbitratorPubKey = offer.getArbitrators().get(0).getPubKey();
registrationPubKey = walletService.getRegistrationAddressEntry().getPubKey();
registrationKeyPair = walletService.getRegistrationAddressEntry().getKeyPair();
addressInfo = walletService.getAddressInfo(offer.getId());
addressEntry = walletService.getAddressEntry(id);
bankAccount = user.getBankAccount(offer.getBankAccountId());
accountId = user.getAccountId();
networkPubKey = user.getNetworkPubKey();
@ -81,6 +83,10 @@ public class OfferSharedModel extends SharedModel {
// getter/setter
public String getId() {
return id;
}
public TradeMessage getTradeMessage() {
return tradeMessage;
}
@ -133,8 +139,8 @@ public class OfferSharedModel extends SharedModel {
return arbitratorPubKey;
}
public AddressEntry getAddressInfo() {
return addressInfo;
public AddressEntry getAddressEntry() {
return addressEntry;
}
}

@ -58,13 +58,11 @@ public class BuyerAsOffererModel extends OfferSharedModel {
private BankAccount takerBankAccount;
private PublicKey takerMessagePublicKey;
private String takerContractAsJson;
private Coin takerPaybackAmount;
private Coin takerPayoutAmount;
private String takeOfferFeeTxId;
private ECKey.ECDSASignature offererSignature;
private Coin offererPaybackAmount;
private Coin offererPayoutAmount;
private List<TransactionOutput> offererConnectedOutputsForAllInputs;
private List<TransactionOutput> offererOutputs;
private Transaction takerDepositTx;
@ -93,8 +91,8 @@ public class BuyerAsOffererModel extends OfferSharedModel {
signatureService,
user);
this.openOffer = openOffer;
offererPubKey = getAddressInfo().getPubKey();
offererPubKey = getAddressEntry().getPubKey();
}
//getter/setter
@ -176,20 +174,20 @@ public class BuyerAsOffererModel extends OfferSharedModel {
this.offererSignature = offererSignature;
}
public Coin getOffererPaybackAmount() {
return offererPaybackAmount;
public Coin getOffererPayoutAmount() {
return offererPayoutAmount;
}
public void setOffererPaybackAmount(Coin offererPaybackAmount) {
this.offererPaybackAmount = offererPaybackAmount;
public void setOffererPayoutAmount(Coin offererPayoutAmount) {
this.offererPayoutAmount = offererPayoutAmount;
}
public Coin getTakerPaybackAmount() {
return takerPaybackAmount;
public Coin getTakerPayoutAmount() {
return takerPayoutAmount;
}
public void setTakerPaybackAmount(Coin takerPaybackAmount) {
this.takerPaybackAmount = takerPaybackAmount;
public void setTakerPayoutAmount(Coin takerPayoutAmount) {
this.takerPayoutAmount = takerPayoutAmount;
}
public void setTrade(Trade trade) {

@ -30,21 +30,21 @@ public class BankTransferStartedMessage implements Serializable, TradeMessage {
private final Transaction depositTx;
private final byte[] offererSignature;
private final Coin offererPaybackAmount;
private final Coin takerPaybackAmount;
private final Coin offererPayoutAmount;
private final Coin takerPayoutAmount;
private final String offererPayoutAddress;
public BankTransferStartedMessage(String tradeId,
Transaction depositTx,
byte[] offererSignature,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
Coin offererPayoutAmount,
Coin takerPayoutAmount,
String offererPayoutAddress) {
this.tradeId = tradeId;
this.depositTx = depositTx;
this.offererSignature = offererSignature;
this.offererPaybackAmount = offererPaybackAmount;
this.takerPaybackAmount = takerPaybackAmount;
this.offererPayoutAmount = offererPayoutAmount;
this.takerPayoutAmount = takerPayoutAmount;
this.offererPayoutAddress = offererPayoutAddress;
}
@ -61,12 +61,12 @@ public class BankTransferStartedMessage implements Serializable, TradeMessage {
return offererPayoutAddress;
}
public Coin getOffererPaybackAmount() {
return offererPaybackAmount;
public Coin getOffererPayoutAmount() {
return offererPayoutAmount;
}
public Coin getTakerPaybackAmount() {
return takerPaybackAmount;
public Coin getTakerPayoutAmount() {
return takerPayoutAmount;
}
public byte[] getOffererSignature() {

@ -40,7 +40,7 @@ public class GetOffererDepositTxInputs extends Task<BuyerAsOffererModel> {
protected void doRun() {
try {
Coin offererInputAmount = model.getTrade().getSecurityDeposit().add(FeePolicy.TX_FEE);
AddressEntry addressInfo = model.getWalletService().getAddressInfo(model.getTrade().getId());
AddressEntry addressInfo = model.getWalletService().getAddressEntry(model.getId());
WalletService.TransactionDataResult result = model.getWalletService().offererCreatesDepositTxInputs(offererInputAmount, addressInfo);
model.setOffererConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());

@ -23,13 +23,11 @@ import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage
import io.bitsquare.util.taskrunner.Task;
import io.bitsquare.util.taskrunner.TaskRunner;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.util.Validator.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessPayoutTxPublishedMessage extends Task<BuyerAsOffererModel> {
private static final Logger log = LoggerFactory.getLogger(ProcessPayoutTxPublishedMessage.class);
@ -41,11 +39,10 @@ public class ProcessPayoutTxPublishedMessage extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
String payoutTxAsHex = nonEmptyStringOf(((PayoutTxPublishedMessage) model.getTradeMessage()).getPayoutTxAsHex());
Transaction payoutTx = new Transaction(model.getWalletService().getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
checkTradeId(model.getId(), model.getTradeMessage());
model.getTrade().setPayoutTx(payoutTx);
model.getTrade().setPayoutTx(checkNotNull(((PayoutTxPublishedMessage) model.getTradeMessage()).getPayoutTx()));
model.getTrade().setState(Trade.State.PAYOUT_PUBLISHED);
complete();

@ -38,13 +38,14 @@ public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOf
@Override
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
checkTradeId(model.getId(), model.getTradeMessage());
RequestOffererPublishDepositTxMessage message = (RequestOffererPublishDepositTxMessage) model.getTradeMessage();
model.setTakerBankAccount(checkNotNull(message.getTakerBankAccount()));
model.setTakerAccountId(nonEmptyStringOf(message.getTakerAccountId()));
model.setTakerMessagePublicKey(checkNotNull(message.getTakerMessagePublicKey()));
model.setTakerContractAsJson(nonEmptyStringOf(message.getTakerContractAsJson()));
model.setTakerPayoutAddress(nonEmptyStringOf(message.getTakerPayoutAddress()));
model.setTakerDepositTx(checkNotNull(message.getTakersDepositTx()));
model.setTakerConnectedOutputsForAllInputs(checkNotNull(message.getTakerConnectedOutputsForAllInputs()));
checkArgument(message.getTakerConnectedOutputsForAllInputs().size() > 0);

@ -39,7 +39,7 @@ public class ProcessTakeOfferFeePayedMessage extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
checkTradeId(model.getId(), model.getTradeMessage());
Trade trade = model.getTrade();
TakeOfferFeePayedMessage takeOfferFeePayedMessage = (TakeOfferFeePayedMessage) model.getTradeMessage();
trade.setTakeOfferFeeTxID(nonEmptyStringOf(takeOfferFeePayedMessage.getTakeOfferFeeTxId()));

@ -37,7 +37,7 @@ public class RequestDepositPayment extends Task<BuyerAsOffererModel> {
protected void doRun() {
model.getOffererPubKey();
RequestDepositPaymentMessage tradeMessage = new RequestDepositPaymentMessage(
model.getTrade().getId(),
model.getId(),
model.getOffererConnectedOutputsForAllInputs(),
model.getOffererOutputs(),
model.getOffererPubKey(),

@ -36,12 +36,12 @@ public class SendBankTransferStartedMessage extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
BankTransferStartedMessage tradeMessage = new BankTransferStartedMessage(
model.getTrade().getId(),
model.getId(),
model.getPublishedDepositTx(),
model.getOffererSignature().encodeToDER(),
model.getOffererPaybackAmount(),
model.getTakerPaybackAmount(),
model.getAddressInfo().getAddressString());
model.getOffererPayoutAmount(),
model.getTakerPayoutAmount(),
model.getWalletService().getAddressEntry(model.getId()).getAddressString());
model.getTradeMessageService().sendMessage(model.getTaker(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {

@ -35,7 +35,7 @@ public class SendDepositTxIdToTaker extends Task<BuyerAsOffererModel> {
@Override
protected void doRun() {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(model.getTrade().getId(), model.getTrade().getDepositTx());
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(model.getId(), model.getTrade().getDepositTx());
model.getTradeMessageService().sendMessage(model.getTaker(), tradeMessage, new SendMessageListener() {
@Override

@ -44,7 +44,7 @@ public class SignAndPublishDepositTx extends Task<BuyerAsOffererModel> {
protected void doRun() {
try {
Coin offererInputAmount = model.getTrade().getSecurityDeposit().add(FeePolicy.TX_FEE);
model.getWalletService().offererSignAndPublishTx(
model.getWalletService().offererSignsAndPublishTx(
model.getTakerDepositTx(),
model.getOffererConnectedOutputsForAllInputs(),
model.getTakerConnectedOutputsForAllInputs(),

@ -17,16 +17,13 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererModel;
import io.bitsquare.util.taskrunner.Task;
import io.bitsquare.util.taskrunner.TaskRunner;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Transaction;
import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -43,20 +40,20 @@ public class SignPayoutTx extends Task<BuyerAsOffererModel> {
try {
Trade trade = model.getTrade();
Coin securityDeposit = trade.getSecurityDeposit();
Coin offererPaybackAmount = trade.getTradeAmount().add(securityDeposit);
@SuppressWarnings("UnnecessaryLocalVariable") Coin takerPaybackAmount = securityDeposit;
Coin offererPayoutAmount = trade.getTradeAmount().add(securityDeposit);
Coin takerPayoutAmount = securityDeposit;
Pair<ECKey.ECDSASignature, Transaction> result = model.getWalletService().offererCreatesAndSignsPayoutTx(
trade.getDepositTx().getHashAsString(),
offererPaybackAmount,
takerPaybackAmount,
model.getTakerPayoutAddress(),
model.getTrade().getId());
WalletService.TransactionDataResult result = model.getWalletService().offererCreatesAndSignsPayoutTx(
trade.getDepositTx(),
offererPayoutAmount,
takerPayoutAmount,
model.getTakerPayoutAddress(),
model.getWalletService().getAddressEntry(trade.getId()));
model.setOffererPayoutTx(result.getValue());
model.setOffererSignature(result.getKey());
model.setOffererPaybackAmount(offererPaybackAmount);
model.setTakerPaybackAmount(takerPaybackAmount);
model.setOffererPayoutTx(result.getPayoutTx());
model.setOffererSignature(result.getOffererSignature());
model.setOffererPayoutAmount(offererPayoutAmount);
model.setTakerPayoutAmount(takerPayoutAmount);
complete();
} catch (Exception e) {

@ -28,6 +28,7 @@ import io.bitsquare.trade.protocol.trade.OfferSharedModel;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
@ -52,11 +53,10 @@ public class SellerAsTakerModel extends OfferSharedModel {
private Transaction depositTx;
private Transaction signedTakerDepositTx;
private Transaction payoutTx;
private String payoutTxAsHex;
private Coin takerPaybackAmount;
private Coin takerPayoutAmount;
private byte[] offererPubKey;
private long offererTxOutIndex;
private Coin offererPaybackAmount;
private Coin offererPayoutAmount;
private String offererPayoutAddress;
private List<TransactionOutput> offererConnectedOutputsForAllInputs;
private List<TransactionOutput> offererOutputs;
@ -66,6 +66,7 @@ public class SellerAsTakerModel extends OfferSharedModel {
private Transaction publishedDepositTx;
private BankAccount takerBankAccount;
private String takerAccountId;
private ECKey.ECDSASignature offererSignature;
public SellerAsTakerModel(Trade trade,
TradeMessageService tradeMessageService,
@ -81,7 +82,7 @@ public class SellerAsTakerModel extends OfferSharedModel {
user);
this.trade = trade;
takerPubKey = getAddressInfo().getPubKey();
takerPubKey = getAddressEntry().getPubKey();
}
// getter/setter
@ -129,14 +130,6 @@ public class SellerAsTakerModel extends OfferSharedModel {
this.payoutTx = payoutTx;
}
public String getPayoutTxAsHex() {
return payoutTxAsHex;
}
public void setPayoutTxAsHex(String payoutTxAsHex) {
this.payoutTxAsHex = payoutTxAsHex;
}
public byte[] getOffererPubKey() {
return offererPubKey;
}
@ -166,20 +159,20 @@ public class SellerAsTakerModel extends OfferSharedModel {
this.depositTx = depositTx;
}
public Coin getOffererPaybackAmount() {
return offererPaybackAmount;
public Coin getOffererPayoutAmount() {
return offererPayoutAmount;
}
public void setOffererPaybackAmount(Coin offererPaybackAmount) {
this.offererPaybackAmount = offererPaybackAmount;
public void setOffererPayoutAmount(Coin offererPayoutAmount) {
this.offererPayoutAmount = offererPayoutAmount;
}
public Coin getTakerPaybackAmount() {
return takerPaybackAmount;
public Coin getTakerPayoutAmount() {
return takerPayoutAmount;
}
public void setTakerPaybackAmount(Coin takerPaybackAmount) {
this.takerPaybackAmount = takerPaybackAmount;
public void setTakerPayoutAmount(Coin takerPayoutAmount) {
this.takerPayoutAmount = takerPayoutAmount;
}
public String getOffererPayoutAddress() {
@ -246,4 +239,12 @@ public class SellerAsTakerModel extends OfferSharedModel {
public String getTakerAccountId() {
return takerAccountId;
}
public ECKey.ECDSASignature getOffererSignature() {
return offererSignature;
}
public void setOffererSignature(ECKey.ECDSASignature offererSignature) {
this.offererSignature = offererSignature;
}
}

@ -19,16 +19,18 @@ package io.bitsquare.trade.protocol.trade.taker.messages;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import org.bitcoinj.core.Transaction;
import java.io.Serializable;
public class PayoutTxPublishedMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = 1288653559218403873L;
private final String tradeId;
private final String payoutTxAsHex;
private final Transaction payoutTx;
public PayoutTxPublishedMessage(String tradeId, String payoutTxAsHex) {
public PayoutTxPublishedMessage(String tradeId, Transaction payoutTx) {
this.tradeId = tradeId;
this.payoutTxAsHex = payoutTxAsHex;
this.payoutTx = payoutTx;
}
@Override
@ -36,7 +38,7 @@ public class PayoutTxPublishedMessage implements Serializable, TradeMessage {
return tradeId;
}
public String getPayoutTxAsHex() {
return payoutTxAsHex;
public Transaction getPayoutTx() {
return payoutTx;
}
}

@ -37,6 +37,7 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
private final PublicKey takerMessagePublicKey;
private final String contractAsJson;
private final String takerContractSignature;
private String takerPayoutAddress;
private Transaction takersDepositTx;
private List<TransactionOutput> takerConnectedOutputsForAllInputs;
private List<TransactionOutput> takerOutputs;
@ -47,6 +48,7 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
PublicKey takerMessagePublicKey,
String contractAsJson,
String takerContractSignature,
String takerPayoutAddress,
Transaction takersDepositTx,
List<TransactionOutput> takerConnectedOutputsForAllInputs,
List<TransactionOutput> takerOutputs) {
@ -56,6 +58,7 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
this.takerMessagePublicKey = takerMessagePublicKey;
this.contractAsJson = contractAsJson;
this.takerContractSignature = takerContractSignature;
this.takerPayoutAddress = takerPayoutAddress;
this.takersDepositTx = takersDepositTx;
this.takerConnectedOutputsForAllInputs = takerConnectedOutputsForAllInputs;
this.takerOutputs = takerOutputs;
@ -103,6 +106,10 @@ public class RequestOffererPublishDepositTxMessage implements Serializable, Trad
return contractAsJson;
}
public String getTakerPayoutAddress() {
return takerPayoutAddress;
}
public Transaction getTakersDepositTx() {
return takersDepositTx;
}

@ -42,7 +42,7 @@ public class PayTakeOfferFee extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
try {
model.getWalletService().payTakeOfferFee(model.getTrade().getId(), new FutureCallback<Transaction>() {
model.getWalletService().payTakeOfferFee(model.getId(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString());

@ -22,9 +22,12 @@ import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.taskrunner.Task;
import io.bitsquare.util.taskrunner.TaskRunner;
import org.bitcoinj.core.ECKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.*;
public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel> {
@ -37,13 +40,13 @@ public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel>
@Override
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
checkTradeId(model.getId(), model.getTradeMessage());
BankTransferStartedMessage message = (BankTransferStartedMessage) model.getTradeMessage();
//model.setDepositTx(checkNotNull(message.getDepositTx()));
//model.setOffererSignature(checkNotNull(ECKey.ECDSASignature.decodeFromDER(message.getOffererSignature())));
model.setOffererPaybackAmount(positiveCoinOf(nonZeroCoinOf(message.getOffererPaybackAmount())));
model.setTakerPaybackAmount(positiveCoinOf(nonZeroCoinOf(message.getTakerPaybackAmount())));
model.setDepositTx(checkNotNull(message.getDepositTx()));
model.setOffererSignature(checkNotNull(ECKey.ECDSASignature.decodeFromDER(message.getOffererSignature())));
model.setOffererPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.getOffererPayoutAmount())));
model.setTakerPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.getTakerPayoutAmount())));
model.setOffererPayoutAddress(nonEmptyStringOf(message.getOffererPayoutAddress()));
complete();

@ -38,7 +38,7 @@ public class ProcessDepositTxPublishedMessage extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
checkTradeId(model.getId(), model.getTradeMessage());
DepositTxPublishedMessage message = (DepositTxPublishedMessage) model.getTradeMessage();
model.setPublishedDepositTx(checkNotNull(message.getDepositTx()));

@ -38,7 +38,7 @@ public class ProcessRequestDepositPaymentMessage extends Task<SellerAsTakerModel
@Override
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
checkTradeId(model.getId(), model.getTradeMessage());
RequestDepositPaymentMessage message = (RequestDepositPaymentMessage) model.getTradeMessage();
model.setOffererConnectedOutputsForAllInputs(checkNotNull(message.getOffererConnectedOutputsForAllInputs()));

@ -38,7 +38,7 @@ public class ProcessRespondToTakeOfferRequestMessage extends Task<SellerAsTakerM
@Override
protected void doRun() {
try {
checkTradeId(model.getTrade().getId(), model.getTradeMessage());
checkTradeId(model.getId(), model.getTradeMessage());
if (((RespondToTakeOfferRequestMessage) model.getTradeMessage()).isOfferIsAvailable()) {
model.getTrade().setState(Trade.State.OFFERER_ACCEPTED);

@ -36,7 +36,7 @@ public class RequestTakeOffer extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
model.getTradeMessageService().sendMessage(model.getOfferer(), new RequestTakeOfferMessage(model.getTrade().getId()),
model.getTradeMessageService().sendMessage(model.getOfferer(), new RequestTakeOfferMessage(model.getId()),
new SendMessageListener() {
@Override
public void handleResult() {

@ -35,7 +35,7 @@ public class SendPayoutTxToOfferer extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(model.getTrade().getId(), model.getPayoutTxAsHex());
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(model.getId(), model.getPayoutTx());
model.getTradeMessageService().sendMessage(model.getOfferer(), tradeMessage, new SendMessageListener() {
@Override
public void handleResult() {

@ -36,12 +36,13 @@ public class SendSignedTakerDepositTx extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(
model.getTrade().getId(),
model.getId(),
model.getBankAccount(),
model.getAccountId(),
model.getNetworkPubKey(),
model.getTrade().getContractAsJson(),
model.getTrade().getTakerContractSignature(),
model.getWalletService().getAddressEntry(model.getId()).getAddressString(),
model.getTakerDepositTx(),
model.getTakerConnectedOutputsForAllInputs(),
model.getTakerOutputs()

@ -39,7 +39,7 @@ public class SendTakeOfferFeePayedMessage extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(
model.getTrade().getId(),
model.getId(),
model.getTrade().getTakeOfferFeeTxId(),
model.getTrade().getTradeAmount(),
model.getTakerPubKey()

@ -22,7 +22,6 @@ import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerModel;
import io.bitsquare.util.taskrunner.Task;
import io.bitsquare.util.taskrunner.TaskRunner;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils;
@ -43,20 +42,20 @@ public class SignAndPublishPayoutTx extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
try {
model.getWalletService().takerSignsAndSendsTx(model.getPublishedDepositTx(),
null,
model.getOffererPaybackAmount(),
model.getTakerPaybackAmount(),
model.getWalletService().takerSignsAndPublishPayoutTx(
model.getPublishedDepositTx(),
model.getOffererSignature(),
model.getOffererPayoutAmount(),
model.getTakerPayoutAmount(),
model.getOffererPayoutAddress(),
model.getTrade().getId(),
model.getAddressEntry(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("takerSignsAndSendsTx " + transaction);
log.debug("published payoutTx " + transaction);
String payoutTxAsHex = Utils.HEX.encode(transaction.bitcoinSerialize());
model.setPayoutTx(transaction);
model.setPayoutTxAsHex(payoutTxAsHex);
model.getTrade().setState(Trade.State.PAYOUT_PUBLISHED);
complete();
@ -67,7 +66,7 @@ public class SignAndPublishPayoutTx extends Task<SellerAsTakerModel> {
failed(t);
}
});
} catch (AddressFormatException e) {
} catch (Throwable e) {
failed(e);
}
}

@ -37,7 +37,7 @@ public class TakerCommitDepositTx extends Task<SellerAsTakerModel> {
@Override
protected void doRun() {
try {
Transaction transaction = model.getWalletService().takerCommitDepositTx(model.getPublishedDepositTx());
Transaction transaction = model.getWalletService().takerCommitsDepositTx(model.getPublishedDepositTx());
model.getTrade().setDepositTx(transaction);
model.getTrade().setState(Trade.State.DEPOSIT_PUBLISHED);

@ -47,7 +47,7 @@ public class TakerCreatesAndSignsDepositTx extends Task<SellerAsTakerModel> {
msOutputAmount,
model.getOffererConnectedOutputsForAllInputs(),
model.getOffererOutputs(),
model.getAddressInfo(),
model.getAddressEntry(),
model.getOffererPubKey(),
model.getTakerPubKey(),
model.getArbitratorPubKey());

@ -145,7 +145,7 @@ public class PlaceOfferProtocolTest {
() -> {
log.trace("wallet completed");
// 1. Use that address for funding the trading wallet
address = walletService.getAddressInfo(OFFER_ID).getAddress();
address = walletService.getAddressEntry(OFFER_ID).getAddress();
log.info("address for funding wallet = " + address.toString());//muoTvFHJmQwPKYoA8Fr7t87UCSfZM4fciG
log.info("Balance = " + walletService.getBalanceForAddress(address));
countDownLatch.countDown();
@ -280,7 +280,7 @@ public class PlaceOfferProtocolTest {
FaultHandler faultHandler = (message, throwable) -> {
log.error(message);
throwable.printStackTrace();
log.info("Balance = " + walletService.getBalanceForAddress(walletService.getAddressInfoByTradeID(OFFER_ID).getAddress()));
log.info("Balance = " + walletService.getBalanceForAddress(walletService.getAddressEntryByTradeID(OFFER_ID).getAddress()));
};
return getPlaceOfferProtocol(offer, resultHandler, faultHandler);
}