Search in sources :

Example 1 with RawTransactionInput

use of io.bitsquare.btc.data.RawTransactionInput in project bitsquare by bitsquare.

the class SignAndPublishDepositTxAsSeller method run.

@Override
protected void run() {
    try {
        runInterceptHook();
        log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n");
        byte[] contractHash = Hash.getHash(trade.getContractAsJson());
        trade.setContractHash(contractHash);
        ArrayList<RawTransactionInput> sellerInputs = processModel.getRawTransactionInputs();
        WalletService walletService = processModel.getWalletService();
        AddressEntry sellerMultiSigAddressEntry = walletService.getOrCreateAddressEntry(processModel.getOffer().getId(), AddressEntry.Context.MULTI_SIG);
        sellerMultiSigAddressEntry.setCoinLockedInMultiSig(Coin.valueOf(sellerInputs.stream().mapToLong(input -> input.value).sum()).subtract(FeePolicy.getFixedTxFeeForTrades(trade.getOffer())));
        TradingPeer tradingPeer = processModel.tradingPeer;
        Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(true, contractHash, processModel.getPreparedDepositTx(), tradingPeer.getRawTransactionInputs(), sellerInputs, tradingPeer.getMultiSigPubKey(), sellerMultiSigAddressEntry.getPubKey(), trade.getArbitratorPubKey(), new FutureCallback<Transaction>() {

            @Override
            public void onSuccess(Transaction transaction) {
                log.trace("takerSignAndPublishTx succeeded " + transaction);
                trade.setDepositTx(transaction);
                trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
                complete();
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                failed(t);
            }
        });
        trade.setDepositTx(depositTx);
    } catch (Throwable t) {
        failed(t);
    }
}
Also used : TradingPeer(io.bitsquare.trade.protocol.trade.TradingPeer) Transaction(org.bitcoinj.core.Transaction) AddressEntry(io.bitsquare.btc.AddressEntry) RawTransactionInput(io.bitsquare.btc.data.RawTransactionInput) WalletService(io.bitsquare.btc.WalletService)

Example 2 with RawTransactionInput

use of io.bitsquare.btc.data.RawTransactionInput in project bitsquare by bitsquare.

the class TradeWalletService method offererCreatesAndSignsDepositTx.

/**
     * The offerer creates the deposit transaction using the takers input(s) and optional output and signs his input(s).
     *
     * @param offererIsBuyer            The flag indicating if we are in the offerer as buyer role or the opposite.
     * @param contractHash              The hash of the contract to be added to the OP_RETURN output.
     * @param offererInputAmount        The input amount of the offerer.
     * @param msOutputAmount            The output amount to our MS output.
     * @param takerRawTransactionInputs Raw data for the connected outputs for all inputs of the taker (normally 1 input)
     * @param takerChangeOutputValue    Optional taker change output value
     * @param takerChangeAddressString  Optional taker change address
     * @param offererAddress            The offerer's address.
     * @param offererChangeAddress      The offerer's change address.
     * @param buyerPubKey               The public key of the buyer.
     * @param sellerPubKey              The public key of the seller.
     * @param arbitratorPubKey          The public key of the arbitrator.
     * @return A data container holding the serialized transaction and the offerer raw inputs
     * @throws SigningException
     * @throws TransactionVerificationException
     * @throws WalletException
     */
public PreparedDepositTxAndOffererInputs offererCreatesAndSignsDepositTx(boolean offererIsBuyer, byte[] contractHash, Coin offererInputAmount, Coin msOutputAmount, List<RawTransactionInput> takerRawTransactionInputs, long takerChangeOutputValue, @Nullable String takerChangeAddressString, Address offererAddress, Address offererChangeAddress, byte[] buyerPubKey, byte[] sellerPubKey, byte[] arbitratorPubKey) throws SigningException, TransactionVerificationException, WalletException, AddressFormatException {
    log.trace("offererCreatesAndSignsDepositTx called");
    log.trace("offererIsBuyer " + offererIsBuyer);
    log.trace("offererInputAmount " + offererInputAmount.toFriendlyString());
    log.trace("msOutputAmount " + msOutputAmount.toFriendlyString());
    log.trace("takerRawInputs " + takerRawTransactionInputs.toString());
    log.trace("takerChangeOutputValue " + takerChangeOutputValue);
    log.trace("takerChangeAddressString " + takerChangeAddressString);
    log.trace("offererAddress " + offererAddress);
    log.trace("offererChangeAddress " + offererChangeAddress);
    log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
    log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
    log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
    checkArgument(!takerRawTransactionInputs.isEmpty());
    // First we construct a dummy TX to get the inputs and outputs we want to use for the real deposit tx. 
    // Similar to the way we did in the createTakerDepositTxInputs method.
    Transaction dummyTx = new Transaction(params);
    Coin dummyOutputAmount = offererInputAmount.subtract(FeePolicy.getFixedTxFeeForTrades());
    TransactionOutput dummyOutput = new TransactionOutput(params, dummyTx, dummyOutputAmount, new ECKey().toAddress(params));
    dummyTx.addOutput(dummyOutput);
    addAvailableInputsAndChangeOutputs(dummyTx, offererAddress, offererChangeAddress);
    // Normally we have only 1 input but we support multiple inputs if the user has paid in with several transactions.
    List<TransactionInput> offererInputs = dummyTx.getInputs();
    TransactionOutput offererOutput = null;
    // We don't support more then 1 optional change output
    Preconditions.checkArgument(dummyTx.getOutputs().size() < 3, "dummyTx.getOutputs().size() >= 3");
    // Only save change outputs, the dummy output is ignored (that's why we start with index 1)
    if (dummyTx.getOutputs().size() > 1)
        offererOutput = dummyTx.getOutput(1);
    // Now we construct the real deposit tx
    Transaction preparedDepositTx = new Transaction(params);
    ArrayList<RawTransactionInput> offererRawTransactionInputs = new ArrayList<>();
    if (offererIsBuyer) {
        // Add buyer inputs
        for (TransactionInput input : offererInputs) {
            preparedDepositTx.addInput(input);
            offererRawTransactionInputs.add(getRawInputFromTransactionInput(input));
        }
        // the sellers input is not signed so we attach empty script bytes
        for (RawTransactionInput rawTransactionInput : takerRawTransactionInputs) preparedDepositTx.addInput(getTransactionInput(preparedDepositTx, new byte[] {}, rawTransactionInput));
    } else {
        // the sellers input is not signed so we attach empty script bytes
        for (RawTransactionInput rawTransactionInput : takerRawTransactionInputs) preparedDepositTx.addInput(getTransactionInput(preparedDepositTx, new byte[] {}, rawTransactionInput));
        // Add seller inputs
        for (TransactionInput input : offererInputs) {
            preparedDepositTx.addInput(input);
            offererRawTransactionInputs.add(getRawInputFromTransactionInput(input));
        }
    }
    // Add MultiSig output
    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);
    // We add the hash ot OP_RETURN with a 0 amount output
    TransactionOutput contractHashOutput = new TransactionOutput(params, preparedDepositTx, Coin.ZERO, ScriptBuilder.createOpReturnScript(contractHash).getProgram());
    preparedDepositTx.addOutput(contractHashOutput);
    TransactionOutput takerTransactionOutput = null;
    if (takerChangeOutputValue > 0 && takerChangeAddressString != null)
        takerTransactionOutput = new TransactionOutput(params, preparedDepositTx, Coin.valueOf(takerChangeOutputValue), new Address(params, takerChangeAddressString));
    if (offererIsBuyer) {
        // Add optional buyer outputs 
        if (offererOutput != null)
            preparedDepositTx.addOutput(offererOutput);
        // Add optional seller outputs 
        if (takerTransactionOutput != null)
            preparedDepositTx.addOutput(takerTransactionOutput);
    } else {
        // Add optional seller outputs 
        if (takerTransactionOutput != null)
            preparedDepositTx.addOutput(takerTransactionOutput);
        // Add optional buyer outputs 
        if (offererOutput != null)
            preparedDepositTx.addOutput(offererOutput);
    }
    // Sign inputs 
    int start = offererIsBuyer ? 0 : takerRawTransactionInputs.size();
    int end = offererIsBuyer ? offererInputs.size() : preparedDepositTx.getInputs().size();
    for (int i = start; i < end; i++) {
        TransactionInput input = preparedDepositTx.getInput(i);
        signInput(preparedDepositTx, input, i);
        checkScriptSig(preparedDepositTx, input, i);
    }
    verifyTransaction(preparedDepositTx);
    return new PreparedDepositTxAndOffererInputs(offererRawTransactionInputs, preparedDepositTx.bitcoinSerialize());
}
Also used : Script(org.bitcoinj.script.Script) RawTransactionInput(io.bitsquare.btc.data.RawTransactionInput) ArrayList(java.util.ArrayList) RawTransactionInput(io.bitsquare.btc.data.RawTransactionInput) PreparedDepositTxAndOffererInputs(io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs)

Example 3 with RawTransactionInput

use of io.bitsquare.btc.data.RawTransactionInput in project bitsquare by bitsquare.

the class TradeWalletService method takerSignsAndPublishesDepositTx.

/**
     * The taker signs the deposit transaction he received from the offerer and publishes it.
     *
     * @param takerIsSeller               The flag indicating if we are in the taker as seller role or the opposite.
     * @param contractHash                The hash of the contract to be added to the OP_RETURN output.
     * @param offerersDepositTxSerialized The prepared deposit transaction signed by the offerer.
     * @param buyerInputs                 The connected outputs for all inputs of the buyer.
     * @param sellerInputs                The connected outputs for all inputs of the seller.
     * @param buyerPubKey                 The public key of the buyer.
     * @param sellerPubKey                The public key of the seller.
     * @param arbitratorPubKey            The public key of the arbitrator.
     * @param callback                    Callback when transaction is broadcasted.
     * @throws SigningException
     * @throws TransactionVerificationException
     * @throws WalletException
     */
public Transaction takerSignsAndPublishesDepositTx(boolean takerIsSeller, byte[] contractHash, byte[] offerersDepositTxSerialized, List<RawTransactionInput> buyerInputs, List<RawTransactionInput> sellerInputs, byte[] buyerPubKey, byte[] sellerPubKey, byte[] arbitratorPubKey, FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException, WalletException {
    Transaction offerersDepositTx = new Transaction(params, offerersDepositTxSerialized);
    log.trace("signAndPublishDepositTx called");
    log.trace("takerIsSeller " + takerIsSeller);
    log.trace("offerersDepositTx " + offerersDepositTx.toString());
    log.trace("buyerConnectedOutputsForAllInputs " + buyerInputs.toString());
    log.trace("sellerConnectedOutputsForAllInputs " + sellerInputs.toString());
    log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
    log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
    log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
    checkArgument(!buyerInputs.isEmpty());
    checkArgument(!sellerInputs.isEmpty());
    // Check if offerer's Multisig script is identical to the takers
    Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    if (!offerersDepositTx.getOutput(0).getScriptPubKey().equals(p2SHMultiSigOutputScript))
        throw new TransactionVerificationException("Offerer's p2SHMultiSigOutputScript does not match to takers p2SHMultiSigOutputScript");
    // The outpoints are not available from the serialized offerersDepositTx, so we cannot use that tx directly, but we use it to construct a new 
    // depositTx
    Transaction depositTx = new Transaction(params);
    if (takerIsSeller) {
        // We grab the signature from the offerersDepositTx and apply it to the new tx input
        for (int i = 0; i < buyerInputs.size(); i++) depositTx.addInput(getTransactionInput(depositTx, getScriptProgram(offerersDepositTx, i), buyerInputs.get(i)));
        // Add seller inputs 
        for (RawTransactionInput rawTransactionInput : sellerInputs) depositTx.addInput(getTransactionInput(depositTx, new byte[] {}, rawTransactionInput));
    } else {
        // Add buyer inputs and apply signature
        for (RawTransactionInput rawTransactionInput : buyerInputs) depositTx.addInput(getTransactionInput(depositTx, new byte[] {}, rawTransactionInput));
        // We grab the signature from the offerersDepositTx and apply it to the new tx input
        for (int i = buyerInputs.size(), k = 0; i < offerersDepositTx.getInputs().size(); i++, k++) depositTx.addInput(getTransactionInput(depositTx, getScriptProgram(offerersDepositTx, i), sellerInputs.get(k)));
    }
    // Check if OP_RETURN output with contract hash matches the one from the offerer
    TransactionOutput contractHashOutput = new TransactionOutput(params, offerersDepositTx, Coin.ZERO, ScriptBuilder.createOpReturnScript(contractHash).getProgram());
    log.debug("contractHashOutput " + contractHashOutput);
    TransactionOutput offerersContractHashOutput = offerersDepositTx.getOutputs().get(1);
    log.debug("offerersContractHashOutput " + offerersContractHashOutput);
    if (!offerersContractHashOutput.getScriptPubKey().equals(contractHashOutput.getScriptPubKey()))
        throw new TransactionVerificationException("Offerer's transaction output for the contract hash is not matching takers version.");
    // Add all outputs from offerersDepositTx to depositTx
    offerersDepositTx.getOutputs().forEach(depositTx::addOutput);
    //printTxWithInputs("offerersDepositTx", offerersDepositTx);
    // Sign inputs 
    int start = takerIsSeller ? buyerInputs.size() : 0;
    int end = takerIsSeller ? depositTx.getInputs().size() : buyerInputs.size();
    for (int i = start; i < end; i++) {
        TransactionInput input = depositTx.getInput(i);
        signInput(depositTx, input, i);
        checkScriptSig(depositTx, input, i);
    }
    printTxWithInputs("depositTx", depositTx);
    verifyTransaction(depositTx);
    checkWalletConsistency();
    // Broadcast depositTx
    checkNotNull(walletAppKit);
    ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(depositTx).future();
    Futures.addCallback(broadcastComplete, callback);
    return depositTx;
}
Also used : Script(org.bitcoinj.script.Script) TransactionVerificationException(io.bitsquare.btc.exceptions.TransactionVerificationException) RawTransactionInput(io.bitsquare.btc.data.RawTransactionInput) RawTransactionInput(io.bitsquare.btc.data.RawTransactionInput)

Example 4 with RawTransactionInput

use of io.bitsquare.btc.data.RawTransactionInput in project bitsquare by bitsquare.

the class SignAndPublishDepositTxAsBuyer method run.

@Override
protected void run() {
    try {
        runInterceptHook();
        log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n");
        byte[] contractHash = Hash.getHash(trade.getContractAsJson());
        trade.setContractHash(contractHash);
        ArrayList<RawTransactionInput> buyerInputs = processModel.getRawTransactionInputs();
        WalletService walletService = processModel.getWalletService();
        AddressEntry buyerMultiSigAddressEntry = walletService.getOrCreateAddressEntry(processModel.getOffer().getId(), AddressEntry.Context.MULTI_SIG);
        Coin buyerInput = Coin.valueOf(buyerInputs.stream().mapToLong(input -> input.value).sum());
        buyerMultiSigAddressEntry.setCoinLockedInMultiSig(buyerInput.subtract(FeePolicy.getFixedTxFeeForTrades(trade.getOffer())));
        TradingPeer tradingPeer = processModel.tradingPeer;
        Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(false, contractHash, processModel.getPreparedDepositTx(), buyerInputs, tradingPeer.getRawTransactionInputs(), buyerMultiSigAddressEntry.getPubKey(), tradingPeer.getMultiSigPubKey(), trade.getArbitratorPubKey(), new FutureCallback<Transaction>() {

            @Override
            public void onSuccess(Transaction transaction) {
                log.trace("takerSignAndPublishTx succeeded " + transaction);
                trade.setDepositTx(transaction);
                trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
                complete();
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                failed(t);
            }
        });
        trade.setDepositTx(depositTx);
    } catch (Throwable t) {
        failed(t);
    }
}
Also used : Coin(org.bitcoinj.core.Coin) TradingPeer(io.bitsquare.trade.protocol.trade.TradingPeer) Transaction(org.bitcoinj.core.Transaction) AddressEntry(io.bitsquare.btc.AddressEntry) RawTransactionInput(io.bitsquare.btc.data.RawTransactionInput) WalletService(io.bitsquare.btc.WalletService)

Aggregations

RawTransactionInput (io.bitsquare.btc.data.RawTransactionInput)4 AddressEntry (io.bitsquare.btc.AddressEntry)2 WalletService (io.bitsquare.btc.WalletService)2 TradingPeer (io.bitsquare.trade.protocol.trade.TradingPeer)2 Transaction (org.bitcoinj.core.Transaction)2 Script (org.bitcoinj.script.Script)2 PreparedDepositTxAndOffererInputs (io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs)1 TransactionVerificationException (io.bitsquare.btc.exceptions.TransactionVerificationException)1 ArrayList (java.util.ArrayList)1 Coin (org.bitcoinj.core.Coin)1