Closed ambitious922 closed 5 months ago
The code you provided is incomplete and it is difficult for us to help you.
I think you can provide a complete and runnable example or a separate github repo for us to debug.
It looks like you are attempting to create and sign a Taproot transaction using bitcoinjs-lib
and the Node.js environment. There are several issues in your code related to creating and adding inputs and outputs, as well as the signing and finalizing process. Let's go through your code and correct the mistakes to make it functional.
Here's a step-by-step guide and corrected code:
Ensure all required libraries are imported and environment variables are set correctly.
const bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
const ecc = require('tiny-secp256k1');
const BIP32Factory = require('bip32').default;
const ECPairFactory = require('ecpair').default;
const fetch = require('node-fetch');
const assert = require('assert');
require('dotenv').config();
bitcoin.initEccLib(ecc);
const bip32 = BIP32Factory(ecc);
const network = bitcoin.networks.testnet;
const expectedAddress = "tb1p2kclfdlyf35z2cz6r05ptx45utsypyjxzmj4ftm0tr2xq55yd47qtnh4j5";
const privateKeyWIF = process.env.PRIVATE_KEY_WIF;
const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
const path = `m/86'/0'/0'/0/0`; // Path to first child of receiving wallet on first account
const receiverAddress = "tb1pwzwkht8gzm39933ytfzf3uks89a5h4cvkfjwml3m5xceu4eshw3sz83wtw";
const runeId = "2585883:3795";
const ECPair = ECPairFactory(ecc);
const keyPair = ECPair.fromWIF(privateKeyWIF, network);
const internalPubkey = keyPair.publicKey.slice(1, 33); // Get x-only pubkey
const seed = await bip39.mnemonicToSeed(mnemonic);
const rootKey = bip32.fromSeed(seed, network);
const childNode = rootKey.derivePath(path);
// Since internalKey is an xOnly pubkey, we drop the DER header byte
const childNodeXOnlyPubkey = internalPubkey;
assert.deepEqual(childNodeXOnlyPubkey, internalPubkey);
const { address, output } = bitcoin.payments.p2tr({
internalPubkey: childNodeXOnlyPubkey,
network,
});
assert(output);
assert.strictEqual(address, expectedAddress);
const tweakedChildNode = childNode.tweak(
bitcoin.crypto.taggedHash("TapTweak", childNodeXOnlyPubkey)
);
console.log("address", address);
Replace your utxos
array with data fetched from Blockcypher and Unisat APIs. Make sure your utxos
have the correct format.
The main issue in your original code was related to the handling of script types and encoding. Let's correct that:
export async function createTransferTransaction() {
const utxosResponse = await fetch(`https://api.blockcypher.com/v1/btc/test3/addrs/${address}?unspentOnly=true`);
const utxosData = await utxosResponse.json();
const runeUtxosResponse = await fetch(`https://wallet-api-testnet.unisat.io/v5/runes/utxos?address=${address}&runeid=2585883:3795`);
const runeUtxosData = await runeUtxosResponse.json();
const utxos = utxosData.txrefs.map(utxo => ({
hash: utxo.tx_hash,
index: utxo.tx_output_n,
value: utxo.value,
script: output.toString('hex'), // Adjust if necessary
}));
const psbt = new bitcoin.Psbt({ network });
for (let utxo of utxos) {
psbt.addInput({
hash: utxo.hash,
index: utxo.index,
witnessUtxo: {
script: Buffer.from(utxo.script, 'hex'),
value: utxo.value,
},
tapInternalKey: toXOnly(internalPubkey),
});
}
const outputScript = bitcoin.script.compile([
bitcoin.opcodes.OP_RETURN,
Buffer.from(runeId),
]);
psbt.addOutput({
address: receiverAddress,
value: 546,
});
psbt.addOutput({
address: address,
value: 546,
});
psbt.addOutput({
script: outputScript,
value: 0,
});
psbt.addOutput({
address: address,
value: utxos.reduce((acc, utxo) => acc + utxo.value, 0) - 1092, // Adjust for actual fee
});
for (let i = 0; i < utxos.length; i++) {
psbt.signInput(i, tweakedChildNode);
}
psbt.finalizeAllInputs();
const rawTxHex = psbt.extractTransaction().toHex();
console.log('Raw Transaction Hex:', rawTxHex);
return rawTxHex;
}
createTransferTransaction().catch(console.error);
Initialize Variables and Fetch UTXOs: Ensure all necessary libraries are imported and initialize all required variables. Fetch UTXOs from the relevant APIs and format them correctly.
Generate Internal Public Key: Generate the internal public key using the private key and BIP32 derivation.
Create and Add Inputs and Outputs: Create the PSBT, add inputs and outputs correctly. Ensure the scripts are correctly encoded in hexadecimal format.
Sign and Finalize the Transaction: Sign each input with the appropriate key and finalize the transaction.
This code should help you generate the correct transaction hex without using Blockcypher. Make sure to test it with your actual data and environment.
Please help me with this error.