Java Code Examples for org.bitcoinj.crypto.DeterministicKey#isEncrypted()

The following examples show how to use org.bitcoinj.crypto.DeterministicKey#isEncrypted() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: TradeWalletService.java    From bisq with GNU Affero General Public License v3.0 6 votes vote down vote up
public byte[] signDelayedPayoutTx(Transaction delayedPayoutTx,
                                  DeterministicKey myMultiSigKeyPair,
                                  byte[] buyerPubKey,
                                  byte[] sellerPubKey)
        throws AddressFormatException, TransactionVerificationException {

    Script redeemScript = get2of2MultiSigRedeemScript(buyerPubKey, sellerPubKey);
    Sha256Hash sigHash = delayedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(myMultiSigKeyPair, "myMultiSigKeyPair must not be null");
    if (myMultiSigKeyPair.isEncrypted()) {
        checkNotNull(aesKey);
    }

    ECKey.ECDSASignature mySignature = myMultiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();
    WalletService.printTx("delayedPayoutTx for sig creation", delayedPayoutTx);
    WalletService.verifyTransaction(delayedPayoutTx);
    return mySignature.encodeToDER();
}
 
Example 2
Source File: TradeWalletService.java    From bisq with GNU Affero General Public License v3.0 6 votes vote down vote up
/**
 * Seller signs payout transaction, buyer has not signed yet.
 *
 * @param depositTx                 deposit transaction
 * @param buyerPayoutAmount         payout amount for buyer
 * @param sellerPayoutAmount        payout amount for seller
 * @param buyerPayoutAddressString  address for buyer
 * @param sellerPayoutAddressString address for seller
 * @param multiSigKeyPair           DeterministicKey for MultiSig from seller
 * @param buyerPubKey               the public key of the buyer
 * @param sellerPubKey              the public key of the seller
 * @return DER encoded canonical signature
 * @throws AddressFormatException if the buyer or seller base58 address doesn't parse or its checksum is invalid
 * @throws TransactionVerificationException if there was an unexpected problem with the payout tx or its signature
 */
public byte[] buyerSignsPayoutTx(Transaction depositTx,
                                 Coin buyerPayoutAmount,
                                 Coin sellerPayoutAmount,
                                 String buyerPayoutAddressString,
                                 String sellerPayoutAddressString,
                                 DeterministicKey multiSigKeyPair,
                                 byte[] buyerPubKey,
                                 byte[] sellerPubKey)
        throws AddressFormatException, TransactionVerificationException {
    Transaction preparedPayoutTx = createPayoutTx(depositTx, buyerPayoutAmount, sellerPayoutAmount,
            buyerPayoutAddressString, sellerPayoutAddressString);
    // MS redeemScript
    Script redeemScript = get2of2MultiSigRedeemScript(buyerPubKey, sellerPubKey);
    // MS output from prev. tx is index 0
    Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(multiSigKeyPair, "multiSigKeyPair must not be null");
    if (multiSigKeyPair.isEncrypted()) {
        checkNotNull(aesKey);
    }
    ECKey.ECDSASignature buyerSignature = multiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();
    WalletService.printTx("prepared payoutTx", preparedPayoutTx);
    WalletService.verifyTransaction(preparedPayoutTx);
    return buyerSignature.encodeToDER();
}
 
Example 3
Source File: TradeWalletService.java    From bisq with GNU Affero General Public License v3.0 6 votes vote down vote up
public byte[] signMediatedPayoutTx(Transaction depositTx,
                                   Coin buyerPayoutAmount,
                                   Coin sellerPayoutAmount,
                                   String buyerPayoutAddressString,
                                   String sellerPayoutAddressString,
                                   DeterministicKey myMultiSigKeyPair,
                                   byte[] buyerPubKey,
                                   byte[] sellerPubKey)
        throws AddressFormatException, TransactionVerificationException {
    Transaction preparedPayoutTx = createPayoutTx(depositTx, buyerPayoutAmount, sellerPayoutAmount, buyerPayoutAddressString, sellerPayoutAddressString);
    // MS redeemScript
    Script redeemScript = get2of2MultiSigRedeemScript(buyerPubKey, sellerPubKey);
    // MS output from prev. tx is index 0
    Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(myMultiSigKeyPair, "myMultiSigKeyPair must not be null");
    if (myMultiSigKeyPair.isEncrypted()) {
        checkNotNull(aesKey);
    }
    ECKey.ECDSASignature mySignature = myMultiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();
    WalletService.printTx("prepared mediated payoutTx for sig creation", preparedPayoutTx);
    WalletService.verifyTransaction(preparedPayoutTx);
    return mySignature.encodeToDER();
}
 
Example 4
Source File: TradeWalletService.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
/**
 * Seller creates and signs payout transaction and adds signature of buyer to complete the transaction.
 *
 * @param depositTx                 deposit transaction
 * @param buyerSignature            DER encoded canonical signature of buyer
 * @param buyerPayoutAmount         payout amount for buyer
 * @param sellerPayoutAmount        payout amount for seller
 * @param buyerPayoutAddressString  address for buyer
 * @param sellerPayoutAddressString address for seller
 * @param multiSigKeyPair           seller's key pair for MultiSig
 * @param buyerPubKey               the public key of the buyer
 * @param sellerPubKey              the public key of the seller
 * @return the payout transaction
 * @throws AddressFormatException if the buyer or seller base58 address doesn't parse or its checksum is invalid
 * @throws TransactionVerificationException if there was an unexpected problem with the payout tx or its signatures
 * @throws WalletException if the seller's wallet is null or structurally inconsistent
 */
public Transaction sellerSignsAndFinalizesPayoutTx(Transaction depositTx,
                                                   byte[] buyerSignature,
                                                   Coin buyerPayoutAmount,
                                                   Coin sellerPayoutAmount,
                                                   String buyerPayoutAddressString,
                                                   String sellerPayoutAddressString,
                                                   DeterministicKey multiSigKeyPair,
                                                   byte[] buyerPubKey,
                                                   byte[] sellerPubKey)
        throws AddressFormatException, TransactionVerificationException, WalletException {
    Transaction payoutTx = createPayoutTx(depositTx, buyerPayoutAmount, sellerPayoutAmount, buyerPayoutAddressString, sellerPayoutAddressString);
    // MS redeemScript
    Script redeemScript = get2of2MultiSigRedeemScript(buyerPubKey, sellerPubKey);
    // MS output from prev. tx is index 0
    Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(multiSigKeyPair, "multiSigKeyPair must not be null");
    if (multiSigKeyPair.isEncrypted()) {
        checkNotNull(aesKey);
    }
    ECKey.ECDSASignature sellerSignature = multiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();
    TransactionSignature buyerTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(buyerSignature),
            Transaction.SigHash.ALL, false);
    TransactionSignature sellerTxSig = new TransactionSignature(sellerSignature, Transaction.SigHash.ALL, false);
    // Take care of order of signatures. Need to be reversed here. See comment below at getMultiSigRedeemScript (seller, buyer)
    Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(sellerTxSig, buyerTxSig),
            redeemScript);
    TransactionInput input = payoutTx.getInput(0);
    input.setScriptSig(inputScript);
    WalletService.printTx("payoutTx", payoutTx);
    WalletService.verifyTransaction(payoutTx);
    WalletService.checkWalletConsistency(wallet);
    WalletService.checkScriptSig(payoutTx, input, 0);
    checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
    input.verify(input.getConnectedOutput());
    return payoutTx;
}
 
Example 5
Source File: TradeWalletService.java    From bisq-core with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
 * Seller signs payout transaction, buyer has not signed yet.
 *
 * @param depositTx                 Deposit transaction
 * @param buyerPayoutAmount         Payout amount for buyer
 * @param sellerPayoutAmount        Payout amount for seller
 * @param buyerPayoutAddressString  Address for buyer
 * @param sellerPayoutAddressString Address for seller
 * @param multiSigKeyPair           DeterministicKey for MultiSig from 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.
 * @return DER encoded canonical signature
 * @throws AddressFormatException
 * @throws TransactionVerificationException
 */
public byte[] buyerSignsPayoutTx(Transaction depositTx,
                                 Coin buyerPayoutAmount,
                                 Coin sellerPayoutAmount,
                                 String buyerPayoutAddressString,
                                 String sellerPayoutAddressString,
                                 DeterministicKey multiSigKeyPair,
                                 byte[] buyerPubKey,
                                 byte[] sellerPubKey,
                                 byte[] arbitratorPubKey)
        throws AddressFormatException, TransactionVerificationException {
    log.trace("sellerSignsPayoutTx called");
    log.trace("depositTx " + depositTx.toString());
    log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
    log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
    log.trace("buyerPayoutAddressString " + buyerPayoutAddressString);
    log.trace("sellerPayoutAddressString " + sellerPayoutAddressString);
    log.trace("multiSigKeyPair (not displayed for security reasons)");
    log.info("buyerPubKey HEX=" + ECKey.fromPublicOnly(buyerPubKey).getPublicKeyAsHex());
    log.info("sellerPubKey HEX=" + ECKey.fromPublicOnly(sellerPubKey).getPublicKeyAsHex());
    log.info("arbitratorPubKey HEX=" + ECKey.fromPublicOnly(arbitratorPubKey).getPublicKeyAsHex());
    Transaction preparedPayoutTx = createPayoutTx(depositTx,
            buyerPayoutAmount,
            sellerPayoutAmount,
            buyerPayoutAddressString,
            sellerPayoutAddressString);
    // MS redeemScript
    Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    // MS output from prev. tx is index 0
    Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(multiSigKeyPair, "multiSigKeyPair must not be null");
    if (multiSigKeyPair.isEncrypted())
        checkNotNull(aesKey);

    ECKey.ECDSASignature buyerSignature = multiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();

    WalletService.printTx("prepared payoutTx", preparedPayoutTx);

    WalletService.verifyTransaction(preparedPayoutTx);

    return buyerSignature.encodeToDER();
}
 
Example 6
Source File: TradeWalletService.java    From bisq-core with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
 * Buyer creates and signs payout transaction and adds signature of seller to complete the transaction
 *
 * @param depositTx                 Deposit transaction
 * @param buyerSignature            DER encoded canonical signature of seller
 * @param buyerPayoutAmount         Payout amount for buyer
 * @param sellerPayoutAmount        Payout amount for seller
 * @param buyerPayoutAddressString  Address for buyer
 * @param sellerPayoutAddressString Address for seller
 * @param multiSigKeyPair           Buyer's keypair for MultiSig
 * @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 The payout transaction
 * @throws AddressFormatException
 * @throws TransactionVerificationException
 * @throws WalletException
 */
public Transaction sellerSignsAndFinalizesPayoutTx(Transaction depositTx,
                                                   byte[] buyerSignature,
                                                   Coin buyerPayoutAmount,
                                                   Coin sellerPayoutAmount,
                                                   String buyerPayoutAddressString,
                                                   String sellerPayoutAddressString,
                                                   DeterministicKey multiSigKeyPair,
                                                   byte[] buyerPubKey,
                                                   byte[] sellerPubKey,
                                                   byte[] arbitratorPubKey)
        throws AddressFormatException, TransactionVerificationException, WalletException {
    log.trace("buyerSignsAndFinalizesPayoutTx 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("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
    log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
    log.trace("buyerPayoutAddressString " + buyerPayoutAddressString);
    log.trace("sellerPayoutAddressString " + sellerPayoutAddressString);
    log.trace("multiSigKeyPair (not displayed for security reasons)");
    log.info("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
    log.info("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
    log.info("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());

    Transaction payoutTx = createPayoutTx(depositTx,
            buyerPayoutAmount,
            sellerPayoutAmount,
            buyerPayoutAddressString,
            sellerPayoutAddressString);
    // MS redeemScript
    Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    // MS output from prev. tx is index 0
    Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(multiSigKeyPair, "multiSigKeyPair must not be null");
    if (multiSigKeyPair.isEncrypted())
        checkNotNull(aesKey);


    ECKey.ECDSASignature sellerSignature = multiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();

    TransactionSignature buyerTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(buyerSignature),
            Transaction.SigHash.ALL, false);
    TransactionSignature sellerTxSig = new TransactionSignature(sellerSignature, Transaction.SigHash.ALL, false);
    // Take care of order of signatures. Need to be reversed here. See comment below at getMultiSigRedeemScript (arbitrator, seller, buyer)
    Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(sellerTxSig, buyerTxSig), redeemScript);

    TransactionInput input = payoutTx.getInput(0);
    input.setScriptSig(inputScript);

    WalletService.printTx("payoutTx", payoutTx);

    WalletService.verifyTransaction(payoutTx);
    WalletService.checkWalletConsistency(wallet);
    WalletService.checkScriptSig(payoutTx, input, 0);
    checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
    input.verify(input.getConnectedOutput());
    return payoutTx;
}
 
Example 7
Source File: TradeWalletService.java    From bisq-core with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
 * That arbitrator signs the payout transaction
 *
 * @param depositTxSerialized Serialized deposit tx
 * @param buyerPayoutAmount   The payout amount of the buyer.
 * @param sellerPayoutAmount  The payout amount of the seller.
 * @param buyerAddressString  The address of the buyer.
 * @param sellerAddressString The address of the seller.
 * @param arbitratorKeyPair   The keypair of the arbitrator.
 * @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 DER encoded canonical signature of arbitrator
 * @throws AddressFormatException
 * @throws TransactionVerificationException
 */
public byte[] arbitratorSignsDisputedPayoutTx(byte[] depositTxSerialized,
                                              Coin buyerPayoutAmount,
                                              Coin sellerPayoutAmount,
                                              String buyerAddressString,
                                              String sellerAddressString,
                                              DeterministicKey arbitratorKeyPair,
                                              byte[] buyerPubKey,
                                              byte[] sellerPubKey,
                                              byte[] arbitratorPubKey)
        throws AddressFormatException, TransactionVerificationException {
    Transaction depositTx = new Transaction(params, depositTxSerialized);
    log.trace("signDisputedPayoutTx called");
    log.trace("depositTx " + depositTx.toString());
    log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
    log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
    log.trace("buyerAddressString " + buyerAddressString);
    log.trace("sellerAddressString " + sellerAddressString);
    log.trace("arbitratorKeyPair (not displayed for security reasons)");
    log.info("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
    log.info("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
    log.info("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());

    // Our MS is index 0
    TransactionOutput p2SHMultiSigOutput = depositTx.getOutput(0);
    Transaction preparedPayoutTx = new Transaction(params);
    preparedPayoutTx.addInput(p2SHMultiSigOutput);
    if (buyerPayoutAmount.isGreaterThan(Coin.ZERO))
        preparedPayoutTx.addOutput(buyerPayoutAmount, Address.fromBase58(params, buyerAddressString));
    if (sellerPayoutAmount.isGreaterThan(Coin.ZERO))
        preparedPayoutTx.addOutput(sellerPayoutAmount, Address.fromBase58(params, sellerAddressString));

    // take care of sorting!
    Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(arbitratorKeyPair, "arbitratorKeyPair must not be null");
    if (arbitratorKeyPair.isEncrypted())
        checkNotNull(aesKey);

    ECKey.ECDSASignature arbitratorSignature = arbitratorKeyPair.sign(sigHash, aesKey).toCanonicalised();

    WalletService.verifyTransaction(preparedPayoutTx);

    //WalletService.printTx("preparedPayoutTx", preparedPayoutTx);

    return arbitratorSignature.encodeToDER();
}
 
Example 8
Source File: TradeWalletService.java    From bisq-core with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
 * A trader who got the signed tx from the arbitrator finalizes the payout tx
 *
 * @param depositTxSerialized    Serialized deposit tx
 * @param arbitratorSignature    DER encoded canonical signature of arbitrator
 * @param buyerPayoutAmount      Payout amount of the buyer
 * @param sellerPayoutAmount     Payout amount of the seller
 * @param buyerAddressString     The address of the buyer.
 * @param sellerAddressString    The address of the seller.
 * @param tradersMultiSigKeyPair The keypair for the MultiSig of the trader who calls that method
 * @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 The completed payout tx
 * @throws AddressFormatException
 * @throws TransactionVerificationException
 * @throws WalletException
 */
public Transaction traderSignAndFinalizeDisputedPayoutTx(byte[] depositTxSerialized,
                                                         byte[] arbitratorSignature,
                                                         Coin buyerPayoutAmount,
                                                         Coin sellerPayoutAmount,
                                                         String buyerAddressString,
                                                         String sellerAddressString,
                                                         DeterministicKey tradersMultiSigKeyPair,
                                                         byte[] buyerPubKey,
                                                         byte[] sellerPubKey,
                                                         byte[] arbitratorPubKey)
        throws AddressFormatException, TransactionVerificationException, WalletException {
    Transaction depositTx = new Transaction(params, depositTxSerialized);

    log.trace("signAndFinalizeDisputedPayoutTx called");
    log.trace("depositTx " + depositTx);
    log.trace("arbitratorSignature r " + ECKey.ECDSASignature.decodeFromDER(arbitratorSignature).r.toString());
    log.trace("arbitratorSignature s " + ECKey.ECDSASignature.decodeFromDER(arbitratorSignature).s.toString());
    log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
    log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
    log.trace("buyerAddressString " + buyerAddressString);
    log.trace("sellerAddressString " + sellerAddressString);
    log.trace("tradersMultiSigKeyPair (not displayed for security reasons)");
    log.info("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
    log.info("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
    log.info("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());


    TransactionOutput p2SHMultiSigOutput = depositTx.getOutput(0);
    Transaction payoutTx = new Transaction(params);
    payoutTx.addInput(p2SHMultiSigOutput);
    if (buyerPayoutAmount.isGreaterThan(Coin.ZERO))
        payoutTx.addOutput(buyerPayoutAmount, Address.fromBase58(params, buyerAddressString));
    if (sellerPayoutAmount.isGreaterThan(Coin.ZERO))
        payoutTx.addOutput(sellerPayoutAmount, Address.fromBase58(params, sellerAddressString));

    // take care of sorting!
    Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(tradersMultiSigKeyPair, "tradersMultiSigKeyPair must not be null");
    if (tradersMultiSigKeyPair.isEncrypted())
        checkNotNull(aesKey);
    ECKey.ECDSASignature tradersSignature = tradersMultiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();

    TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
    TransactionSignature arbitratorTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(arbitratorSignature),
            Transaction.SigHash.ALL, false);
    // Take care of order of signatures. See comment below at getMultiSigRedeemScript (sort order needed here: arbitrator, seller, buyer)
    Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(arbitratorTxSig, tradersTxSig), redeemScript);
    TransactionInput input = payoutTx.getInput(0);
    input.setScriptSig(inputScript);

    WalletService.printTx("disputed payoutTx", payoutTx);

    WalletService.verifyTransaction(payoutTx);
    WalletService.checkWalletConsistency(wallet);
    WalletService.checkScriptSig(payoutTx, input, 0);
    checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
    input.verify(input.getConnectedOutput());
    return payoutTx;
}
 
Example 9
Source File: TradeWalletService.java    From bisq with GNU Affero General Public License v3.0 4 votes vote down vote up
/**
 * A trader who got the signed tx from the arbitrator finalizes the payout tx.
 *
 * @param depositTxSerialized    serialized deposit tx
 * @param arbitratorSignature    DER encoded canonical signature of arbitrator
 * @param buyerPayoutAmount      payout amount of the buyer
 * @param sellerPayoutAmount     payout amount of the seller
 * @param buyerAddressString     the address of the buyer
 * @param sellerAddressString    the address of the seller
 * @param tradersMultiSigKeyPair the key pair for the MultiSig of the trader who calls that method
 * @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 the completed payout tx
 * @throws AddressFormatException if the buyer or seller base58 address doesn't parse or its checksum is invalid
 * @throws TransactionVerificationException if there was an unexpected problem with the payout tx or its signature
 * @throws WalletException if the trade wallet is null or structurally inconsistent
 */
public Transaction traderSignAndFinalizeDisputedPayoutTx(byte[] depositTxSerialized,
                                                         byte[] arbitratorSignature,
                                                         Coin buyerPayoutAmount,
                                                         Coin sellerPayoutAmount,
                                                         String buyerAddressString,
                                                         String sellerAddressString,
                                                         DeterministicKey tradersMultiSigKeyPair,
                                                         byte[] buyerPubKey,
                                                         byte[] sellerPubKey,
                                                         byte[] arbitratorPubKey)
        throws AddressFormatException, TransactionVerificationException, WalletException {
    Transaction depositTx = new Transaction(params, depositTxSerialized);
    TransactionOutput p2SHMultiSigOutput = depositTx.getOutput(0);
    Transaction payoutTx = new Transaction(params);
    payoutTx.addInput(p2SHMultiSigOutput);
    if (buyerPayoutAmount.isPositive()) {
        payoutTx.addOutput(buyerPayoutAmount, Address.fromBase58(params, buyerAddressString));
    }
    if (sellerPayoutAmount.isPositive()) {
        payoutTx.addOutput(sellerPayoutAmount, Address.fromBase58(params, sellerAddressString));
    }

    // take care of sorting!
    Script redeemScript = get2of3MultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    checkNotNull(tradersMultiSigKeyPair, "tradersMultiSigKeyPair must not be null");
    if (tradersMultiSigKeyPair.isEncrypted()) {
        checkNotNull(aesKey);
    }
    ECKey.ECDSASignature tradersSignature = tradersMultiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();
    TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
    TransactionSignature arbitratorTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(arbitratorSignature),
            Transaction.SigHash.ALL, false);
    // Take care of order of signatures. See comment below at getMultiSigRedeemScript (sort order needed here: arbitrator, seller, buyer)
    Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(arbitratorTxSig, tradersTxSig),
            redeemScript);
    TransactionInput input = payoutTx.getInput(0);
    input.setScriptSig(inputScript);
    WalletService.printTx("disputed payoutTx", payoutTx);
    WalletService.verifyTransaction(payoutTx);
    WalletService.checkWalletConsistency(wallet);
    WalletService.checkScriptSig(payoutTx, input, 0);
    checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
    input.verify(input.getConnectedOutput());
    return payoutTx;
}