UNPKG

@btc-vision/transaction

Version:

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

271 lines 9.79 kB
import { address, fromHex, payments } from '@btc-vision/bitcoin'; import { EcKeyPair } from './EcKeyPair.js'; import { BitcoinUtils } from '../utils/BitcoinUtils.js'; import { P2WDADetector } from '../p2wda/P2WDADetector.js'; import { MLDSASecurityLevel } from '@btc-vision/bip32'; export var AddressTypes; (function (AddressTypes) { AddressTypes["P2PKH"] = "P2PKH"; AddressTypes["P2OP"] = "P2OP"; AddressTypes["P2SH_OR_P2SH_P2WPKH"] = "P2SH_OR_P2SH-P2WPKH"; AddressTypes["P2PK"] = "P2PK"; AddressTypes["P2TR"] = "P2TR"; AddressTypes["P2MR"] = "P2MR"; AddressTypes["P2WPKH"] = "P2WPKH"; AddressTypes["P2WSH"] = "P2WSH"; AddressTypes["P2WDA"] = "P2WDA"; })(AddressTypes || (AddressTypes = {})); export class AddressVerificator { static isValidP2TRAddress(inAddress, network) { if (!inAddress || inAddress.length < 50) return false; let isValidTapRootAddress = false; try { address.toOutputScript(inAddress, network); const decodedAddress = address.fromBech32(inAddress); isValidTapRootAddress = decodedAddress.version === 1; } catch { } return isValidTapRootAddress; } /** * Validates that the given address is a valid P2MR (BIP 360) address. * Checks for witness version 2 with a 32-byte Merkle root program. */ static isValidP2MRAddress(inAddress, network) { if (!inAddress || inAddress.length < 50) return false; let isValidP2MR = false; try { address.toOutputScript(inAddress, network); const decodedAddress = address.fromBech32(inAddress); isValidP2MR = decodedAddress.version === 2 && decodedAddress.data.length === 32; } catch { } return isValidP2MR; } static isP2WPKHAddress(inAddress, network) { if (!inAddress || inAddress.length < 20 || inAddress.length > 50) return false; let isValidSegWitAddress = false; try { const decodedAddress = address.fromBech32(inAddress); address.toOutputScript(inAddress, network); isValidSegWitAddress = decodedAddress.version === 0 && decodedAddress.data.length === 20; } catch { } return isValidSegWitAddress; } static isP2WDAWitnessScript(witnessScript) { return P2WDADetector.isP2WDAWitnessScript(witnessScript); } static isP2PKHOrP2SH(addy, network) { try { const decodedBase58 = address.fromBase58Check(addy); if (decodedBase58.version === network.pubKeyHash) { return true; } return decodedBase58.version === network.scriptHash; } catch (error) { return false; } } static isValidPublicKey(input, network) { try { if (input.startsWith('0x')) { input = input.slice(2); } if (!BitcoinUtils.isValidHex(input)) { return false; } if (input.length === 64) { return true; } const pubKeyBuffer = fromHex(input); if ((input.length === 130 && pubKeyBuffer[0] === 0x06) || pubKeyBuffer[0] === 0x07) { return true; } if (input.length === 66 || input.length === 130) { EcKeyPair.fromPublicKey(pubKeyBuffer, network); return true; } } catch (e) { return false; } return false; } static isValidMLDSAPublicKey(input) { try { let byteLength; if (typeof input !== 'string' && input instanceof Uint8Array) { byteLength = input.length; } else { if (input.startsWith('0x')) { input = input.slice(2); } if (!BitcoinUtils.isValidHex(input)) { return null; } byteLength = input.length / 2; } switch (byteLength) { case 1312: return MLDSASecurityLevel.LEVEL2; case 1952: return MLDSASecurityLevel.LEVEL3; case 2592: return MLDSASecurityLevel.LEVEL5; default: return null; } } catch (e) { return null; } } static isValidP2OPAddress(inAddress, network) { if (!inAddress || inAddress.length < 20) return false; try { const decodedAddress = address.fromBech32(inAddress); const validPrefix = decodedAddress.prefix === network.bech32 || decodedAddress.prefix === network.bech32Opnet; if (!validPrefix) { return false; } return decodedAddress.version === 16 && decodedAddress.data.length === 21; } catch { return false; } } static requireRedeemScript(addy, network) { try { const decodedBase58 = address.fromBase58Check(addy); if (decodedBase58.version === network.pubKeyHash) { return false; } return decodedBase58.version === network.scriptHash; } catch { return false; } } static detectAddressType(addy, network) { if (AddressVerificator.isValidPublicKey(addy, network)) { return AddressTypes.P2PK; } try { const decodedBase58 = address.fromBase58Check(addy); if (decodedBase58.version === network.pubKeyHash) { return AddressTypes.P2PKH; } if (decodedBase58.version === network.scriptHash) { return AddressTypes.P2SH_OR_P2SH_P2WPKH; } } catch { } try { const decodedBech32 = address.fromBech32(addy); if ((decodedBech32.prefix === network.bech32Opnet || decodedBech32.prefix === network.bech32) && decodedBech32.version === 16 && decodedBech32.data.length === 21) { return AddressTypes.P2OP; } if (decodedBech32.prefix === network.bech32) { if (decodedBech32.version === 0 && decodedBech32.data.length === 20) { return AddressTypes.P2WPKH; } if (decodedBech32.version === 0 && decodedBech32.data.length === 32) { return AddressTypes.P2WSH; } if (decodedBech32.version === 1 && decodedBech32.data.length === 32) { return AddressTypes.P2TR; } if (decodedBech32.version === 2 && decodedBech32.data.length === 32) { return AddressTypes.P2MR; } } } catch { } return null; } static detectAddressTypeWithWitnessScript(addy, network, witnessScript) { const baseType = AddressVerificator.detectAddressType(addy, network); if (baseType === AddressTypes.P2WSH && witnessScript) { if (AddressVerificator.isP2WDAWitnessScript(witnessScript)) { return AddressTypes.P2WDA; } } return baseType; } static validateP2WDAAddress(address, network, witnessScript) { try { const addressType = AddressVerificator.detectAddressType(address, network); if (addressType !== AddressTypes.P2WSH) { return { isValid: false, isPotentiallyP2WDA: false, isDefinitelyP2WDA: false, error: 'Not a P2WSH address', }; } if (!witnessScript) { return { isValid: true, isPotentiallyP2WDA: true, isDefinitelyP2WDA: false, }; } if (!AddressVerificator.isP2WDAWitnessScript(witnessScript)) { return { isValid: true, isPotentiallyP2WDA: true, isDefinitelyP2WDA: false, error: 'Witness script does not match P2WDA pattern', }; } const p2wsh = payments.p2wsh({ redeem: { output: witnessScript }, network, }); if (p2wsh.address !== address) { return { isValid: false, isPotentiallyP2WDA: false, isDefinitelyP2WDA: false, error: 'Witness script does not match address', }; } const publicKey = P2WDADetector.extractPublicKeyFromP2WDA(witnessScript); if (!publicKey) { return { isValid: false, isPotentiallyP2WDA: false, isDefinitelyP2WDA: false, error: 'Failed to extract public key from witness script', }; } return { isValid: true, isPotentiallyP2WDA: true, isDefinitelyP2WDA: true, publicKey, }; } catch (error) { return { isValid: false, isPotentiallyP2WDA: false, isDefinitelyP2WDA: false, error: error.message, }; } } } //# sourceMappingURL=AddressVerificator.js.map