I'm trying to sign a transaction but I'm getting below error:
Error: Input #0 has witnessUtxo but non-segwit script: a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed87
Below is my code:
const bitcoin = require('bitcoinjs-lib');
const request = require('request-promise-native');
// const net = bitcoin.networks.bitcoin;
const net = bitcoin.networks.testnet;
const API = net === bitcoin.networks.testnet
? 'https://test-insight.swap.online/insight-api'
: 'https://insight.bitpay.com/api'
const fetchUnspents = (address) =>
request(`${API}/addr/${address}/utxo/`).then(JSON.parse)
(async () => {
const psbt = new bitcoin.Psbt({ network: net });
const alice_pair = bitcoin.ECPair.fromWIF('cR6RdGAojE4TuzRSY16a92vPfKgdjUj3tjHmoaPRcHvxRpTMr8gy', net);
const pubkeys = [alice_pair.publicKey].map(hex => Buffer.from(hex, 'hex'));
const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })});
const unspents = await fetchUnspents(address);
const totalAmount = unspents.reduce((summ, { satoshis }) => summ + satoshis, 0);
const withdrawAmount = 0.001 * 100000000;
const fee = 0.00001 * 100000000;
const change = totalAmount - (withdrawAmount + fee);
unspents.forEach(element => {
psbt.addInput({
hash: element.txid,
index: element.vout,
witnessUtxo: {
script: Buffer.from(element.scriptPubKey, 'hex'),
value: element.amount * 100000000
},
// redeemScript:Buffer.from(element.scriptPubKey)
})
});
psbt.addOutput({
address: '2NBJtjiL8kHb3vGW4b945rgSbh9zasAq7qB',
value: withdrawAmount
});
psbt.addOutput({
address: address,
value: change
});
psbt.signInput(0, alice_pair);
console.log('valid signature: ', psbt.validateSignaturesOfAllInputs());
psbt.finalizeAllInputs();
const rawHex = psbt.extractTransaction().toHex();
console.log(rawHex);
})()
You missed redeemScript into txInput for P2SH
Instead of just grabbing the address, try this:
const p2shObj = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })});
const { address } = p2shObj;
const redeemScript = p2shObj.redeem.output;
Then use redeemScript with addInput.
Let me know if this works.
@rohitsahu21
const pubkeys = [alice_pair.publicKey].map(hex => Buffer.from(hex, 'hex'));
.publicKey already Buffer so above code will raise error. You can write like this
const pubkeys = [alice_pair.publicKey]
Above utxos is not witnessUtxo so you should use nonWitnessUtxo instead. Value of nonWitnessUtxo is Buffer of hex of previous raw tx
A sample inputData is
const p2shObj = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })});
const redeemScript = p2shObj.redeem.output;
psbt.addInput({
hash: 'db87829c15a5e3100c41563bad05d65c129f637f91705628afb16a2b33c50d27',
index: 1,
nonWitnessUtxo: Buffer.from('02000000000101eb64c7ac988c0e3564c35c618127d398835f7176cd6089ef445b14bddf88321c04000000171600144e386df71c94aca6f4304e427e5f326685371ae1feffffff02ba4c2f000000000017a91437bf7c47aa84767161d4f70ed07e4b2d7ddb4ad08740420f000000000017a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed870247304402200a30031e9b85e56a79ec995b31fe83cfcad3aba9188dfc87d5d3f84c252b1c28022045925955d54cdc23866bd16ba0e565a6203406367b1a118667d2327fe210096401210265eb47ee4d7c71385abb4343a150c1d8713303c18bfb9a3b7be3f0ea2c760b323b8e1800', 'hex'),
redeemScript: redeemScript,
});
psbt.signInput(0, alice_pair);
console.log('valid signature: ', psbt.validateSignaturesOfAllInputs()) // return true
@rohitsahu21
const pubkeys = [alice_pair.publicKey].map(hex => Buffer.from(hex, 'hex'));
.publicKeyalreadyBufferso above code will raise error. You can write like thisconst pubkeys = [alice_pair.publicKey]Above utxos is not
witnessUtxoso you should usenonWitnessUtxoinstead. Value of nonWitnessUtxo is Buffer of hex of previous raw txA sample inputData is
const p2shObj = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2ms({ m: 1, pubkeys, network: net })}); const redeemScript = p2shObj.redeem.output; psbt.addInput({ hash: 'db87829c15a5e3100c41563bad05d65c129f637f91705628afb16a2b33c50d27', index: 1, nonWitnessUtxo: Buffer.from('02000000000101eb64c7ac988c0e3564c35c618127d398835f7176cd6089ef445b14bddf88321c04000000171600144e386df71c94aca6f4304e427e5f326685371ae1feffffff02ba4c2f000000000017a91437bf7c47aa84767161d4f70ed07e4b2d7ddb4ad08740420f000000000017a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed870247304402200a30031e9b85e56a79ec995b31fe83cfcad3aba9188dfc87d5d3f84c252b1c28022045925955d54cdc23866bd16ba0e565a6203406367b1a118667d2327fe210096401210265eb47ee4d7c71385abb4343a150c1d8713303c18bfb9a3b7be3f0ea2c760b323b8e1800', 'hex'), redeemScript: redeemScript, });psbt.signInput(0, alice_pair); console.log('valid signature: ', psbt.validateSignaturesOfAllInputs()) // return true
Getting Error: Error: Can not add duplicate data to input
code is here:
unspents.forEach(element => {
psbt.addInput({
hash: element.txid,
index: element.vout,
witnessUtxo: {
script: Buffer.from(element.scriptPubKey, 'hex'),
value: element.amount * 100000000
},
nonWitnessUtxo: Buffer.from('02000000000101eb64c7ac988c0e3564c35c618127d398835f7176cd6089ef445b14bddf88321c04000000171600144e386df71c94aca6f4304e427e5f326685371ae1feffffff02ba4c2f000000000017a91437bf7c47aa84767161d4f70ed07e4b2d7ddb4ad08740420f000000000017a91455e9fceb916ad6cc5fc23b3a8bd2cc8955a436ed870247304402200a30031e9b85e56a79ec995b31fe83cfcad3aba9188dfc87d5d3f84c252b1c28022045925955d54cdc23866bd16ba0e565a6203406367b1a118667d2327fe210096401210265eb47ee4d7c71385abb4343a150c1d8713303c18bfb9a3b7be3f0ea2c760b323b8e1800', 'hex'),
redeemScript: redeemScript
});
});
remove witnessUtxo you don't need it. nonWitnessUtxo has all the info you need.
Give Error:
Error: No signatures to validate
and How to get nonWitnessUtxo String?
Each utxos has a separate raw hex, you are using raw hex from my example for all outputs, which is a duplicate error. So how can get raw hex from txId quickly, You can fetch from this public API then take value of key hex:
https://api.blockcypher.com/v1/btc/test3/txs/<txID here>?includeHex=true
Or using your bitcoind node with getrawtransaction API. https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/getrawtransaction/
give same error:
Error: No signatures to validate
Code is here:
const hashHex = await fetchHash(unspents[0].txid);
// console.log(hashHex);
unspents.forEach(element => {
psbt.addInput({
hash: element.txid,
index: element.vout,
nonWitnessUtxo: Buffer.from(hashHex.hex, 'hex'),
redeemScript: redeemScript
});
});
Error: No signatures to validate
Could you give me the output of console.log(psbt.toBase64()) just before you run validateSignaturesOfAllInputs
signInput should throw an Error if it doesn't sign. So "No signatures" is weird.
Here is the value of psbt.toBase64() :
cHNidP8BAJwCAAAAAicNxTMrarGvKFZwkX9jnxJc1gWtO1ZBDBDjpRWcgofbAQAAAAD/////rBBngcr/W5WpxRx7TuHnC5HNqla2Q4BZmkRB7L5pT3oAAAAAAP////8CoIYBAAAAAAAXqRTGI9ub/bynsfQzafnFhnBhEQdZ5IfI3g0AAAAAABepFFXp/OuRatbMX8I7OovSzIlVpDbthwAAAAAAAQD3AgAAAAABAetkx6yYjA41ZMNcYYEn05iDX3F2zWCJ70RbFL3fiDIcBAAAABcWABROOG33HJSspvQwTkJ+XzJmhTca4f7///8CukwvAAAAAAAXqRQ3v3xHqoR2cWHU9w7QfkstfdtK0IdAQg8AAAAAABepFFXp/OuRatbMX8I7OovSzIlVpDbthwJHMEQCIAowAx6bheVqeeyZWzH+g8/K06upGI38h9XT+EwlKxwoAiBFkllV1UzcI4Zr0Wug5WWmIDQGNnsaEYZn0jJ/4hAJZAEhAmXrR+5NfHE4WrtDQ6FQwdhxMwPBi/uaO3vj8OosdgsyO44YACICAyngcfcbBtO+P6ZFAOrfW4hiCWUSiAwX/4VqO6A6kTeARzBEAiBGuYf9skqvlCK+ZLBw5LHv7uhGlRJDN9WefBkbgEhxywIgL7M51cEM8rtIrdH8XJJ/bbUb0Gw0mFLlh9Lzyd85wAEBAQQlUSEDKeBx9xsG074/pkUA6t9biGIJZRKIDBf/hWo7oDqRN4BRrgABAPcCAAAAAAEB62THrJiMDjVkw1xhgSfTmINfcXbNYInvRFsUvd+IMhwEAAAAFxYAFE44bfcclKym9DBOQn5fMmaFNxrh/v///wK6TC8AAAAAABepFDe/fEeqhHZxYdT3DtB+Sy1920rQh0BCDwAAAAAAF6kUVen865Fq1sxfwjs6i9LMiVWkNu2HAkcwRAIgCjADHpuF5Wp57JlbMf6Dz8rTq6kYjfyH1dP4TCUrHCgCIEWSWVXVTNwjhmvRa6DlZaYgNAY2exoRhmfSMn/iEAlkASECZetH7k18cThau0NDoVDB2HEzA8GL+5o7e+Pw6ix2CzI7jhgAAQQlUSEDKeBx9xsG074/pkUA6t9biGIJZRKIDBf/hWo7oDqRN4BRrgAAAA==
// You need to get the tx for EVERY INPUT INDIVIDUALLY
// const hashHex = await fetchHash(unspents[0].txid);
// console.log(hashHex);
unspents.forEach(element => {
const hashHex = await fetchHash(element.txid);
psbt.addInput({
hash: element.txid,
index: element.vout,
nonWitnessUtxo: Buffer.from(hashHex.hex, 'hex'),
redeemScript: redeemScript
});
});
Run fetchHash on EVERY unspent, then try it.
Hello,
I'm trying to do the same thing, but I have a mistake, if you have an idea :
"Redeem script for input #0 doesn't match the scriptPubKey in the prevout"
function scriptCheckerFactory(payment, paymentScriptName) {
...
if (!scriptPubKey.equals(redeemScriptOutput)) {
throw new Error(
`${paymentScriptName} for input #${inputIndex} doesn't match the scriptPubKey in the prevout`,
);
}
}
scriptPubKey.toString("hex") -> "a914e1767896d84c2489a26666873fc29c864a03b82c87"
redeemScriptOutput.toString("hex") -> "a914f451b792d3f8cd8ba83ef6bed905a3c228dc2dd287"
My code:
const idx = addrs.indexOf(input.address)
//QhA84yRpiKszJSvKaDxa9GHwBRTsKHnQ7C
const ecpair = Bitcoin.ECPair.fromWIF(addrsWallet[idx].private_key, this.network)
const pubkeys = [ecpair.publicKey]
const p2shObj = Bitcoin.payments.p2sh({ redeem: Bitcoin.payments.p2ms(
{ m: 1, pubkeys, network: this.network })
})
const redeemScript = p2shObj.redeem.output
let rawTx="01000000000101282a14a07aa0ca74aa9db4918bb5dc75576795e985d44cea8c94e00189f8d67401000000171600148031e4abb080a77925c3e7818d7dc5787ffda60dffffffff0280841e000000000017a914b232f46999952516ef3c11c070d9a2af8cba1256874a324e3b0000000017a914e1767896d84c2489a26666873fc29c864a03b82c870247304402200f5c5943918ddbd8ffbf112008527c6dd92d0d65beac6556a7c1b4037dc9155702206362d1adf42c750c486970845a85b7cc6e3d3a10453e8bb001960397365fbc81012103dc63d1938cfa6574239042136990c5dfb2987a465fca2b567ac0fdee2bc60efd00000000"
psbt.addInput({
hash: input.txid,
index: input.vout,
witnessUtxo: {
script: Buffer.from(input.scriptPubKey, 'hex'),
value: input.value
},
//nonWitnessUtxo: Buffer.from(rawTx, 'hex'),
redeemScript: redeemScript,
})
psbt.signInput(0, ecpair)
if you have any suggestions....
thanks
You are spending the wrong coins.
scriptPubKey is for address A, and redeemScript is for address B.
The error is very easy to understand.
check to make sure everything is correct.
pubkeys are correctly compressed/uncompressed
No, I'm using the good address.
I found this solution:
I replace this (P2MS: "Pay To Multi-Sig")
const p2shObj = Bitcoin.payments.p2sh({
redeem: Bitcoin.payments.p2ms({ m: 1, pubkeys, network: this.network })
})
by this (P2WPKH: "Pay To Witness Public Key Hash")
const p2shObj = Bitcoin.payments.p2sh({
redeem: Bitcoin.payments.p2wpkh({ pubkey: ecpair.publicKey, network: this.network }),
});
And now I can sign / validateSignaturesOfInput / extractTransaction
No, I'm using the good address
If you were using p2ms instead of p2wpkh then your redeemScript's address was incorrect compared to the address you used to fetch your scriptPubKey.
You fixed it by using the correct payment type.
Thanks for keeping us updated on your status.
For information, the scriptPubKey come from utxo (insight api)
address:"QhA84yRpiKszJSvKaDxa9GHwBRTsKHnQ7C"
amount:0.6
confirmations:50535
height:1232842
satoshis:60000000
scriptPubKey:"a914e1767896d84c2489a26666873fc29c864a03b82c87"
txid:"287f329bfd0c7989c77c341c68a701e1c98d400cd26ce075d97d6851d7bb7043"
vout:0
I will soon do a payment test...and update status
Okay, sending the transaction is working fine!
Thanks for your support.