Hello everybody.
I'm trying to sign a custom P2SH Multisig but i'm having trouble.
From my understanding the "sign" method in TransactionBuilder only accepts a set of standard transactions.
This is my attempt:
var keyPairs = [
"cRmbQiGDNF7FGNuY7PeTS2VTG59s2kHUjVEf65dtFRWV2CJKnkzK",
"cSwigfrwCHr2npxtRhQGUyg87uThQTjscWx6twmYSSzkZT2rB7GC"
].map(function(wif) {
return bitcoin.ECPair.fromWIF(wif, testnet);
});
var pubKeys = keyPairs.map(function(x) {
return x.getPublicKeyBuffer();
});
// 2-2 Multi-sig with an IF statement
var witnessScript = bitcoin.script.compile(
[].concat(ops.IF, ops.OP_RESERVED + 2, pubKeys, ops.OP_RESERVED + 2, ops.OP_CHECKMULTISIG, ops.ENDIF)
);
var witnessScriptHash = bitcoin.crypto.sha256(witnessScript);
var redeemScript = bitcoin.script.witnessScriptHash.output.encode(witnessScriptHash);
var redeemScriptHash = bitcoin.crypto.hash160(redeemScript);
var scriptPubKey = bitcoin.script.scriptHash.output.encode(redeemScriptHash);
var address = bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet);
testnetUtils.faucet(address, 6e4, function(err, unspent) {
if (err) return done(err);
var txb = new bitcoin.TransactionBuilder(testnet);
txb.addInput(unspent.txId, unspent.vout);
txb.addOutput(testnetUtils.RETURN_ADDRESS, 4e4);
txb.sign(0, keyPairs[0], redeemScript, null, unspent.value, scriptPubKey);
txb.sign(0, keyPairs[1], redeemScript, null, unspent.value, scriptPubKey);
// The redeem script should be:
// <sig 1, sig2> 1
// However im unsure on how to do this :(
var tx = txb.build();
// build and broadcast to the Bitcoin Testnet network
testnetUtils.transactions.propagate(tx.toHex(), function(err) {
if (err) return done(err);
testnetUtils.verify(address, tx.getId(), 4e4, done);
});
});
Thanks for your help
TransactionBuilder only supports specific transaction types.
If you'd like to know how to sign, look at the sign function, and create a similar function within your app.
Thanks for you help :)
I'm using the Transaction class to create a raw transaction.
When I broadcast the transaction I get the following error:
Error: 64: non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)
I believe i'm not generating the sig correctly?
var txb = new bitcoin.Transaction();
txb.ins.push({
hash: Buffer.from(unspent.txId, "hex").reverse(),
index: 0,
script: bitcoin.script.compile([redeemScript]),
sequence: 0xffffffff
});
const hash = txb.hashForWitnessV0(0, witnessScript, unspent.value, bitcoin.Transaction.SIGHASH_ALL);
const sig1 = keyPairs[0].sign(hash).toScriptSignature(bitcoin.Transaction.SIGHASH_ALL);
const sig2 = keyPairs[1].sign(hash).toScriptSignature(bitcoin.Transaction.SIGHASH_ALL);
const witness = [sig2, sig1, Buffer.from("01", "hex"), witnessScript];
txb.ins[0].witness = witness;
txb.outs.push({
script: scriptPubKey,
value: 4e4
});
txb.toHex()
you can't add an output after generating the sighash...
Also, be sure that the sig order is correct. Otherwise it will fail.
looks like the null byte for the CHECKMULTISIG is missing also?
Got the following to work, slightly modified the script into an IF/ELSE.
var bitcoin = require('./src/index.js')
var bcrypto = bitcoin.crypto;
var bscript = bitcoin.script;
var ops = require('bitcoin-ops');
var testnet = bitcoin.networks.testnet;
var keyPairs = [
"cRmbQiGDNF7FGNuY7PeTS2VTG59s2kHUjVEf65dtFRWV2CJKnkzK",
"cSwigfrwCHr2npxtRhQGUyg87uThQTjscWx6twmYSSzkZT2rB7GC"
].map(function(wif) {
return bitcoin.ECPair.fromWIF(wif, testnet);
});
var pubKeys = keyPairs.map(function(x) {
return x.getPublicKeyBuffer();
});
// if 2-of-2-multisig else [alice
var scriptParts = [].concat(
ops.OP_IF,
ops.OP_2, pubKeys[0], pubKeys[1], ops.OP_2, ops.OP_CHECKMULTISIG,
ops.OP_ELSE,
pubKeys[1], ops.OP_CHECKSIG,
ops.OP_ENDIF);
var witnessScript = bitcoin.script.compile(
scriptParts
);
console.log(bscript.toASM(scriptParts))
var witnessHash = bcrypto.sha256(witnessScript)
var redeemScript = bscript.witnessScriptHash.output.encode(witnessHash)
var redeemScript160 = bcrypto.hash160(redeemScript)
var value = 100000000
var scriptPubKey = bscript.scriptHash.output.encode(redeemScript160)
var txId = "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234";
var vout = 0
var txb = new bitcoin.Transaction();
txb.ins.push({
hash: Buffer.from(txId, "hex").reverse(),
index: vout,
script: bitcoin.script.compile([redeemScript]),
sequence: 0xffffffff
});
txb.outs.push({
script: scriptPubKey,
value: 90000000
});
var hash = txb.hashForWitnessV0(0, witnessScript, value, bitcoin.Transaction.SIGHASH_ALL);
var sig1 = keyPairs[0].sign(hash).toScriptSignature(bitcoin.Transaction.SIGHASH_ALL);
var sig2 = keyPairs[1].sign(hash).toScriptSignature(bitcoin.Transaction.SIGHASH_ALL);
var witness1 = [Buffer.from("", "hex"), sig1, sig2, Buffer.from("01", "hex"), witnessScript];
txb.ins[0].witness = witness1;
var hex = txb.toHex()
console.log(hex)
var witness2 = [sig2, Buffer.from("", "hex"), witnessScript];
txb.ins[0].witness = witness2;
var hex = txb.toHex()
console.log(hex)
Thank you so much that worked perfectly:
Hopefully I can start contributing soon. :)
Most helpful comment
Got the following to work, slightly modified the script into an IF/ELSE.