Closed danielwpz closed 2 months ago
which method should I call to set the witness? anything else I need to do before broadcasting the transaction? 😵💫
bitcoin.payments.p2sh
with bitcoin.payments.p2wsh
}).input!;
with }).witness!;
setInputScript
with setWitness
unlockScript()
make sure to use hashForWitnessV0
instead of hashForSignature
. (Note: this new signature hash requires the satoshi value of the output that you're spending.)Fixing these 4 things should work fine.
will try, thanks!
hey @junderw , as for the signing, what I did is
const p2wsh = bitcoin.payments.p2wsh({
redeem: {
output: lockScript(),
},
network,
});
const sigHash = spendTx.hashForWitnessV0(
0,
p2wsh.redeem!.output!,
1e5,
bitcoin.Transaction.SIGHASH_ALL,
);
but seems the CHECKSIG failed
Use 3e5
not 1e5
You are signing "This input is spending this much satoshis"
@junderw thanks for the help! it works eventually. I'm posting the entire working script for future reference
import * as bitcoin from "bitcoinjs-lib";
import ECPairFactory, { ECPairInterface } from "ecpair";
import { RegtestUtils } from "regtest-client";
import * as ecc from "tiny-secp256k1";
const regtestUtils = new RegtestUtils({ APIURL: "http://localhost:8080/1" });
const network = regtestUtils.network;
const ECPair = ECPairFactory(ecc);
function idToHash(txid: string): Buffer {
return Buffer.from(txid, 'hex').reverse();
}
function toOutputScript(address: string): Buffer {
return bitcoin.address.toOutputScript(address, network);
}
function lockScript(user: ECPairInterface) {
return bitcoin.script.fromASM(
`
OP_DROP
${user.publicKey.toString("hex")}
OP_CHECKSIG
`
.trim()
.replace(/\s+/g, ' '),
)
}
function unlockScript(user: ECPairInterface, sigHash: Buffer) {
return bitcoin.script.compile([
bitcoin.script.signature.encode(
user.sign(sigHash),
bitcoin.Transaction.SIGHASH_ALL,
),
bitcoin.opcodes.OP_0,
]);
}
async function test() {
const user = ECPair.makeRandom();
const p2wsh = bitcoin.payments.p2wsh({
redeem: {
output: lockScript(user),
},
network,
});
/// -- 1. Fund
const fundUnspent = await regtestUtils.faucet(p2wsh.address!, 3e5);
/// -- 2. Spend
const spendTx = new bitcoin.Transaction();
spendTx.version = 2;
spendTx.addInput(idToHash(fundUnspent.txId), fundUnspent.vout);
// withdraw to user's address
spendTx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 1e5);
const sigHash = spendTx.hashForWitnessV0(
0,
p2wsh.redeem!.output!,
3e5,
bitcoin.Transaction.SIGHASH_ALL,
);
const redeemScriptWitness = bitcoin.payments.p2wsh({
network,
redeem: {
network,
output: p2wsh.redeem!.output!,
input: unlockScript(user, sigHash),
},
}).witness!;
spendTx.setWitness(0, redeemScriptWitness);
await regtestUtils.mine(1);
await regtestUtils.broadcast(spendTx.toHex());
await regtestUtils.verify({
txId: spendTx.getId(),
address: regtestUtils.RANDOM_ADDRESS,
vout: 0,
value: 1e5,
});
}
test();
Hi, I wanna to convert my custom p2sh transaction into a p2wsh one, but failed to make it work. Could anybody kindly help me with that?
btw I have scanned other issues but there is no working p2wsh with custom script exists. There are someone who asked the similar question but when they figured out they didn't post the working code eventually.
The following is my p2sh script: (actual scripts are replaced with some dummy codes but the idea stands)