UNPKG

@btc-vision/transaction

Version:

OPNet transaction library allows you to create and sign transactions for the OPNet network.

130 lines 4.3 kB
import { fromHex, opcodes, payments, script } from '@btc-vision/bitcoin'; /** * P2WDA Detection and Validation Utilities */ export class P2WDADetector { /** * Check if a UTXO is a P2WDA output by examining its script structure */ static isP2WDAUTXO(utxo) { if (!utxo.witnessScript) { return false; } const witnessScript = utxo.witnessScript instanceof Uint8Array ? utxo.witnessScript : fromHex(utxo.witnessScript); return this.isP2WDAWitnessScript(witnessScript); } /** * Check if a witness script follows the P2WDA pattern */ static isP2WDAWitnessScript(witnessScript) { try { const decompiled = script.decompile(witnessScript); if (!decompiled || decompiled.length !== 7) { return false; } // Check for 5 OP_2DROP operations for (let i = 0; i < 5; i++) { if (decompiled[i] !== opcodes.OP_2DROP) { return false; } } // Check for pubkey and OP_CHECKSIG return (decompiled[5] instanceof Uint8Array && decompiled[5].length === 33 && // Compressed public key decompiled[6] === opcodes.OP_CHECKSIG); } catch { return false; } } /** * Generate a P2WDA address from a public key */ static generateP2WDAAddress(publicKey, network) { if (publicKey.length !== 33) { throw new Error('Public key must be 33 bytes (compressed)'); } // Create the P2WDA witness script with 5x OP_2DROP const witnessScript = script.compile([ opcodes.OP_2DROP, opcodes.OP_2DROP, opcodes.OP_2DROP, opcodes.OP_2DROP, opcodes.OP_2DROP, publicKey, opcodes.OP_CHECKSIG, ]); // Wrap in P2WSH const p2wsh = payments.p2wsh({ redeem: { output: witnessScript }, network, }); if (!p2wsh.address || !p2wsh.output) { throw new Error('Failed to generate P2WDA address'); } return { address: p2wsh.address, witnessScript, scriptPubKey: p2wsh.output, }; } /** * Extract the public key from a P2WDA witness script */ static extractPublicKeyFromP2WDA(witnessScript) { try { const decompiled = script.decompile(witnessScript); if (!decompiled || decompiled.length !== 7) { return null; } // Check for 5x OP_2DROP pattern for (let i = 0; i < 5; i++) { if (decompiled[i] !== opcodes.OP_2DROP) { return null; } } if (decompiled[5] instanceof Uint8Array && decompiled[5].length === 33 && decompiled[6] === opcodes.OP_CHECKSIG) { return decompiled[5]; } return null; } catch { return null; } } /** * Create witness data for a simple P2WDA spend (no operation data) */ static createSimpleP2WDAWitness(transactionSignature, witnessScript) { const witnessStack = [transactionSignature]; // Add 10 empty buffers for the 5x OP_2DROP operations for (let i = 0; i < 10; i++) { witnessStack.push(new Uint8Array(0)); } witnessStack.push(witnessScript); return witnessStack; } /** * Validate P2WDA operation data signature */ static validateP2WDASignature(_publicKey, dataSignature, _operationData) { return dataSignature.length === 64; // Schnorr signatures are always 64 bytes } /** * Calculate the witness size for P2WDA transaction estimation */ static estimateP2WDAWitnessSize(dataSize = 0) { return 72 + dataSize + 39 + 12; } /** * Check if a scriptPubKey is a P2WSH that could be P2WDA */ static couldBeP2WDA(scriptPubKey) { return scriptPubKey.length === 34 && scriptPubKey[0] === 0x00 && scriptPubKey[1] === 0x20; } } //# sourceMappingURL=P2WDADetector.js.map