@btc-vision/transaction
Version:
OPNet transaction library allows you to create and sign transactions for the OPNet network.
130 lines • 4.3 kB
JavaScript
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