@vbyte/btc-dev
Version:
Batteries-included toolset for plebian bitcoin development
128 lines (120 loc) • 3.25 kB
text/typescript
import { Buff, Bytes } from '@vbyte/buff'
import { is_valid_script } from '@/lib/script/decode.js'
import { TAPLEAF_VERSIONS } from '@/const.js'
import type {
WitnessData,
SpendScriptType,
WitnessVersion
} from '@/types/index.js'
export function parse_witness (
witness : Bytes[]
) : WitnessData {
// Parse the witness data.
const elems = witness.map(e => Buff.bytes(e))
const stack = witness.map(e => Buff.bytes(e).hex)
const annex = parse_annex_data(elems)
if (annex !== null) elems.pop()
const cblock = parse_cblock_data(elems)
if (cblock !== null) elems.pop()
const type = parse_witness_type(elems, cblock)
const version = parse_witness_version(type)
const script = parse_witness_script(elems, type)
if (script !== null) elems.pop()
const params = elems.map(e => e.hex)
return { annex, cblock, params, script, stack, type, version }
}
function parse_annex_data (
data : Uint8Array[]
) : string | null {
// Get the last element of the array.
let elem = data.at(-1)
// Check if the element fits the annex format.
if (
data.length > 1 &&
elem instanceof Uint8Array &&
elem[0] === 0x50
) {
// Return the element.
return new Buff(elem).hex
} else {
// Return null.
return null
}
}
function parse_cblock_data (
data : Uint8Array[]
) : string | null {
let elem = data.at(-1)
if (
data.length > 1 &&
elem instanceof Uint8Array &&
elem.length > 32 &&
TAPLEAF_VERSIONS.includes(elem[0] & 0xfe)
) {
// Return the element.
return new Buff(elem).hex
} else {
// Return null.
return null
}
}
function parse_witness_script (
elems : Uint8Array[],
type : SpendScriptType | null
) {
let script : Uint8Array | undefined
switch (type) {
case 'p2ts':
script = elems.at(-1)
case 'p2wsh':
script = elems.at(-1)
}
return (script !== undefined) ? new Buff(script).hex : null
}
function parse_witness_type (
elems : Uint8Array[],
cblock : string | null
) : SpendScriptType | null{
// Get the important elements of the witness.
let param_0 = elems.at(0),
param_1 = elems.at(1),
param_x = elems.at(-1)
// If the cblock is present and the last element exists:
if (cblock !== null && param_x !== undefined) {
return 'p2ts'
// If the witness elements match the profile of a p2w-pkh:
} else if (
elems.length === 2 &&
param_0 !== undefined &&
param_1 !== undefined &&
param_0.length >= 64 &&
param_1.length === 33
) {
return 'p2wpkh'
// If the witness elements match the profile of a p2tr-pk:
} else if (
elems.length === 1 &&
param_0 !== undefined &&
param_0.length === 64
) {
return 'p2tr'
// If there is at least two witness elements:
} else if (
elems.length > 1 &&
param_x !== undefined &&
is_valid_script(param_x)
) {
return 'p2wsh'
// If the witness elements don't match any known profile:
} else {
return null
}
}
function parse_witness_version (
type : SpendScriptType | null
) : WitnessVersion | null {
if (type === null) return null
if (type.startsWith('p2w')) return 0
if (type.startsWith('p2t')) return 1
return null
}