Untitled
unknown
javascript
10 months ago
5.0 kB
8
Indexable
const crypto = require('crypto');
const bs58 = require('bs58');
const fs = require('fs');
// Utility functions
const hexToBuffer = (hex) => Buffer.from(hex, 'hex');
const doubleSha256 = (data) => crypto.createHash('sha256').update(crypto.createHash('sha256').update(data).digest()).digest();
const encodeVarint = (n) => n < 0xfd ? [n] : (n <= 0xffff ? [0xfd, n & 0xFF, (n >> 8) & 0xFF] : (n <= 0xffffffff ? [0xfe, n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF, (n >> 24) & 0xFF] : [0xff, ...Array.from({length: 8}, (_, i) => (n >> (i * 8)) & 0xFF)]));
const intToLittleEndian = (val, size) => {
let buf = Buffer.alloc(size);
for (let i = 0; i < size; i++) buf[i] = (val >> (i * 8)) & 0xFF;
return buf;
};
// Base58 address to script conversion (P2PKH or P2SH)
const addressToScript = (address) => {
const decoded = bs58.decode(address);
const hash160 = decoded.slice(1, 21);
return Buffer.concat([Buffer.from([0xa9, 0x14]), hash160, Buffer.from([0x87])]);
};
// Transaction serialization
const serializeOutpoint = (hash, index) => {
const hashBuf = Buffer.from(hash, 'hex').reverse();
const indexBuf = Buffer.alloc(4);
indexBuf.writeUInt32LE(index);
return Buffer.concat([hashBuf, indexBuf]);
};
const serializeInput = (prevHash, prevIndex, script, sequence) => {
const outpoint = serializeOutpoint(prevHash, prevIndex);
const scriptLen = encodeVarint(script.length);
const sequenceBuf = Buffer.alloc(4);
sequenceBuf.writeUInt32LE(sequence);
return Buffer.concat([outpoint, scriptLen, script, sequenceBuf]);
};
const serializeOutput = (value, script) => {
const valueBuf = Buffer.alloc(8);
valueBuf.writeBigUInt64LE(BigInt(value));
const scriptLen = encodeVarint(script.length);
return Buffer.concat([valueBuf, scriptLen, script]);
};
// P2WSH Witness creation
const getP2WSHWitness = (signatures, witnessScript) => {
const witness = [0x04, 0x00]; // OP_0 due to CHECKMULTISIG bug
signatures.forEach(sig => {
witness.push(sig.length, ...sig);
});
witness.push(witnessScript.length, ...witnessScript);
return Buffer.from(witness);
};
// Transaction creation
const createTransaction = () => {
const pubKey1 = hexToBuffer('032ff8c5df0bc00fe1ac2319c3b8070d6d1e04cfbf4fedda499ae7b775185ad53b');
const pubKey2 = hexToBuffer('039bbc8d24f89e5bc44c5b0d1980d6658316a6b2440023117c3c03a4975b04dd56');
const redeemScript = Buffer.concat([Buffer.from([0x52, 0x21]), pubKey1, Buffer.from([0x21]), pubKey2, Buffer.from([0x52, 0xae])]);
const witnessScript = redeemScript;
const witnessProgram = doubleSha256(witnessScript);
const p2wshScript = Buffer.concat([Buffer.from([0x00, 0x20]), witnessProgram]);
const p2shRedeemScript = p2wshScript;
const p2shInputScript = Buffer.concat([Buffer.from([p2shRedeemScript.length]), p2shRedeemScript]);
const version = Buffer.from([0x02, 0x00, 0x00, 0x00]);
const marker = Buffer.from([0x00]);
const flag = Buffer.from([0x01]);
// Inputs and Outputs
const nInputs = encodeVarint(1);
const txInput = serializeInput('0'.repeat(64), 0, p2shInputScript, 0xffffffff);
const nOutputs = encodeVarint(1);
const outputScript = addressToScript('325UUecEQuyrTd28Xs2hvAxdAjHM7XzqVF');
const txOutput = serializeOutput(100000, outputScript);
// Outpoints, sequences, outputs for final tx
const outpoints = [serializeOutpoint('0'.repeat(64), 0)];
const hashPrevouts = doubleSha256(Buffer.concat(outpoints));
const sequences = [Buffer.from([0xff, 0xff, 0xff, 0xff])];
const hashSequence = doubleSha256(Buffer.concat(sequences));
const hashOutputs = doubleSha256(txOutput);
// Preimage for sighash
const preimage = Buffer.concat([
version, hashPrevouts, hashSequence, outpoints[0],
encodeVarint(witnessScript.length), witnessScript,
Buffer.from([100000]), sequences[0], hashOutputs,
Buffer.from([0x00, 0x00, 0x00, 0x00]), Buffer.from([0x01, 0x00, 0x00, 0x00])
]);
const sighash = doubleSha256(preimage);
// Signatures
const signature1 = Buffer.from('304402202335473bc09007ca8d4b738e67ac56a0a75b4f945d8d2fd0452437c15d4e2041022048c08ad5b8f09b304eb36e6ed0c6087d8fccd15d4110d114e856a9580844594701', 'hex');
const signature2 = Buffer.from('30450221009aa7fc343e0d4d1d2298cb80b1b0453dcb0e38fe0af2f707118cb402a87fb0480220658b120004b1a43986b0ccdca723f66b9601c565152dee7631853b139c9746e701', 'hex');
const signatures = [signature1, signature2];
// Generate witness
const witness = getP2WSHWitness(signatures, witnessScript);
// Locktime
const locktime = intToLittleEndian(0x00, 4);
// Final transaction
const finalTx = Buffer.concat([version, marker, flag, nInputs, txInput, nOutputs, txOutput, witness, locktime]);
const txidNew = finalTx.toString('hex');
// Output and save result
console.log(txidNew);
fs.writeFileSync('out.txt', txidNew);
};
// Call the function to create the transaction
createTransaction();
Editor is loading...
Leave a Comment