Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to redeem UTXO with P2SH #7

Closed
peter-jim opened this issue Mar 18, 2024 · 2 comments
Closed

How to redeem UTXO with P2SH #7

peter-jim opened this issue Mar 18, 2024 · 2 comments

Comments

@peter-jim
Copy link

peter-jim commented Mar 18, 2024

I had to send utxo from p2pkh to p2sh address, here is my code .

const bitcoin = require('bitcoinjs-lib');
const ecc = require('tiny-secp256k1');
const ecpair = require('ecpair');
const { buffer } = require('stream/consumers');

const TESTNET = bitcoin.networks.testnet;
const ECPair = ecpair.ECPairFactory(ecc);

const alice = ECPair.fromWIF(
    'xxx',
);

const address = bitcoin.payments.p2pkh({
    pubkey: alice.publicKey,
    network: TESTNET,
});


console.log("alice address", address.address);




const tx = new bitcoin.Transaction(TESTNET);



const txId = "c1e48b3ae44001fb1dddf2958b177ace2c640ce636c32860c85b82431fa3eb13";
const vout = 0;


tx.addInput(Buffer.from(txId, 'hex').reverse(), vout);

// 
// const sha256HashString = bitcoin.crypto.sha256(Buffer.from('Btrust Builders')).toString('hex');


const lockingScript = bitcoin.script.compile([
    bitcoin.opcodes.OP_ADD,
	bitcoin.opcodes.OP_13,
	bitcoin.opcodes.OP_EQUAL
]);


const decompiled = bitcoin.script.decompile(Buffer.from(lockingScript, 'hex')).toString('hex');
console.log('Decompiled Redeem Script:', decompiled);

const p2shAddress = bitcoin.payments.p2sh({
    redeem: { output: lockingScript },
    network: TESTNET
});

console.log('p2shAddress :', p2shAddress.address);


// 
// const outputValue = utxo.value - FEE; // 
tx.addOutput(
    bitcoin.address.toOutputScript(p2shAddress.address, TESTNET),
    800
);

console.log("output ScriptPubKey (HEX)", bitcoin.address.toOutputScript(p2shAddress.address, TESTNET));
const outputScript = bitcoin.address.toOutputScript(p2shAddress.address, TESTNET);
const asmCode = bitcoin.script.toASM(outputScript);
console.log('Output Script ASM:', asmCode);

// 
const hashType = bitcoin.Transaction.SIGHASH_ALL;



const utxoAddress = bitcoin.payments.p2pkh({ pubkey: alice.publicKey, network: TESTNET });
const p2pkhScriptPubKey = bitcoin.address.toOutputScript(utxoAddress.address, TESTNET); //
console.log('toOutputScript',p2pkhScriptPubKey);

const signatureHash = tx.hashForSignature(0, p2pkhScriptPubKey, hashType); // 
console.log("signatureHash",signatureHash.toString('hex'));


const signature = bitcoin.script.signature.encode(alice.sign(signatureHash), hashType);
console.log("signature",signature.toString('hex'));
const scriptSig = bitcoin.script.compile([
  signature,
  alice.publicKey  
]);


console.log("scriptSig",scriptSig.toString('hex'))   //

tx.setInputScript(0, scriptSig);

console.log('Tx Hex:', tx.toHex());

and then I want unlocking this utxo from p2sh tp p2pkh, here is my code

const bitcoin = require('bitcoinjs-lib');
const ecc = require('tiny-secp256k1');
const ecpair = require('ecpair');


const TESTNET = bitcoin.networks.testnet;
const ECPair = ecpair.ECPairFactory(ecc);

const alice = ECPair.fromWIF(
    'xxx',
);

const address = bitcoin.payments.p2pkh({
    pubkey: alice.publicKey,
    network: TESTNET,
});

console.log("alice address", address.address);


// 找到P2SH输出对应的UTXO
const p2shUtxo = {
    txId: "94b5a43de760c4e88c25a7b3642174d5e52a9b5b9334997ce4a50d2b2f8cefec",
    outputIndex: 0,
    address: "2ND8PB9RrfCaAcjfjP1Y6nAgFd9zWHYX4DN",
    value: 300
};



const pubKeyHash = bitcoin.crypto.hash256(alice.publicKey);
console.log("pubKeyHash",pubKeyHash);


const unlockingScript = bitcoin.script.compile([
    bitcoin.opcodes.OP_6,
	bitcoin.opcodes.OP_7,
    bitcoin.opcodes.OP_ADD,
	bitcoin.opcodes.OP_13,
	bitcoin.opcodes.OP_EQUAL

]);

// const data = Buffer.from('Btrust Builders');
const redeemTx = new bitcoin.Transaction(TESTNET);
redeemTx.addInput(Buffer.from(p2shUtxo.txId, 'hex').reverse(), p2shUtxo.outputIndex);
redeemTx.addOutput(bitcoin.address.toOutputScript(address.address, TESTNET), p2shUtxo.value);
// console.log(bitcoin.address.toOutputScript(address.address, TESTNET))  
redeemTx.setInputScript(0, unlockingScript);
console.log('Redeem Tx Hex:', redeemTx.toHex());

When I want broad the hex ,"0100000001ecef8c2f2b0da5e47c9934935b9b2ae5d5742164b3a7258ce8c460e73da4b59400000000055657935d87ffffffff012c010000000000001976a914b163d850125f1b65eadbcf15f88b7ef16836c1ee88ac00000000" I got error mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)

I can make sure my txid and vout is right. How can I solve this problem , thank you

@antonilol
Copy link
Owner

please ask general questions about bitcoin script on the stack exchange, this is not specifically related to this repository, and make sure to use markdown code blocks to make code readable in your post (i edited it for now)

i did spot the error in your code:
p2sh needs the script on the stack top, not the loose opcodes (see https://github.com/antonilol/btc_stuff/blob/master/p2sh.js#L20-L24, the last list element is the compiled redeemScript)
changing a few numbers in your raw transaction makes it valid as i thought (tested with the testmempoolaccept rpc)
0100000001ecef8c2f2b0da5e47c9934935b9b2ae5d5742164b3a7258ce8c460e73da4b5940000000006565703935d87ffffffff012c010000000000001976a914b163d850125f1b65eadbcf15f88b7ef16836c1ee88ac00000000

@peter-jim
Copy link
Author

Yeah,thank for you feedback,It's my fault. publish wrong place,I was going to push it bitcoinjs-lib.

Have a nice day!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants