import { createHash } from "node:crypto";
export function asUint8Array(value) {
if (value instanceof Uint8Array) {
return value;
}
if (ArrayBuffer.isView(value)) {
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
}
if (value instanceof ArrayBuffer) {
return new Uint8Array(value);
}
throw new TypeError("expected Uint8Array-compatible input");
}
export function upperHex(bytes) {
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0").toUpperCase()).join("");
}
export function readU16LE(bytes, offset) {
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint16(offset, true);
}
export function readI16LE(bytes, offset) {
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getInt16(offset, true);
}
export function readU32LE(bytes, offset) {
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset, true);
}
export function readI32LE(bytes, offset) {
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getInt32(offset, true);
}
export function readI64LE(bytes, offset) {
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getBigInt64(offset, true);
}
export function readU64LE(bytes, offset) {
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getBigUint64(offset, true);
}
export function computeChecksum(bytes) {
const first = createHash("sha256").update(Buffer.from(bytes)).digest();
const second = createHash("sha256").update(first).digest();
return new Uint8Array(second.subarray(0, 4));
}
export function computeScriptHash(script) {
const sha256 = createHash("sha256").update(Buffer.from(script)).digest();
const ripemd160 = createHash("ripemd160").update(sha256).digest();
return new Uint8Array(ripemd160);
}
export function scanSlotCounts(instructions) {
for (const instruction of instructions) {
if (
instruction.opcode.mnemonic === "INITSLOT" &&
instruction.operand?.kind === "Bytes" &&
instruction.operand.value.length >= 2
) {
return [instruction.operand.value[0], instruction.operand.value[1]];
}
}
let maxLocal = -1;
let maxArg = -1;
for (const instruction of instructions) {
const mnemonic = instruction.opcode.mnemonic;
if (/^(?:LD|ST)LOC(?:\d+)?$/u.test(mnemonic)) {
maxLocal = Math.max(maxLocal, slotIndex(mnemonic, instruction));
}
if (/^(?:LD|ST)ARG(?:\d+)?$/u.test(mnemonic)) {
maxArg = Math.max(maxArg, slotIndex(mnemonic, instruction));
}
}
return [maxLocal + 1, maxArg + 1];
}
export function scanStaticSlotCount(instructions) {
for (const instruction of instructions) {
if (instruction.opcode.mnemonic === "INITSSLOT" && instruction.operand?.kind === "U8") {
return instruction.operand.value;
}
}
return 0;
}
export function slotIndex(mnemonic, instruction) {
const exact = mnemonic.match(/(?:LD|ST)(?:LOC|ARG|SFLD)(\d+)$/u);
if (exact) {
return Number(exact[1]);
}
if (instruction.operand?.kind === "U8") {
return instruction.operand.value;
}
return 0;
}