🏡 index : ~doyle/blocks.ls.git

import { Buffer } from "buffer/";

export function fromHex(hex: string): Buffer {
  return Buffer.from(hex, "hex");
}

export function getScriptType(bytes: Buffer): string | null {
  if (isP2pk(bytes)) {
    return "P2PK";
  } else if (isP2pkh(bytes)) {
    return "P2PKH";
  } else if (isP2sh(bytes)) {
    return "P2SH";
  } else if (isReturn(bytes)) {
    return "OP_RETURN";
  } else {
    return null;
  }
}

export function takeScriptMessage(asmInput: string[]): string | null {
  try {
    let input = "";

    for (let i = 0; i < asmInput.length; i++) {
      const asm = asmInput[i];

      if (asm.startsWith("OP_PUSHBYTES_")) {
        input += asmInput[i + 1];
        i++;
      }
    }

    if (input) {
      return Buffer.from(input, "hex").toString("ascii").trim();
    } else {
      return null;
    }
  } catch (e) {
    return null;
  }
}

export function hexToAsm(bytes: Buffer) {
  const out = [];

  // adapted from https://gist.github.com/rsbondi/674ec5ac823a244b889773be57304f85
  for (let i = 0; i < bytes.length; i++) {
    const byte = bytes[i];

    if (byte >= 0x52 && byte <= 0x60) {
      out.push((byte - 0x50).toString(16));
      continue;
    }

    if (byte >= 0x02 && byte <= 0x4b) {
      out.push("OP_PUSHBYTES_" + byte);
      out.push(bytes.slice(i + 1, i + 1 + byte).toString("hex"));
      i += byte;
      continue;
    }

    out.push(Operation[byte] || byte.toString(16));
  }

  return out;
}

export function briefHexToAsm(hex: Buffer) {
  const asm = hexToAsm(hex);

  const OP_RETURN = Operation[Operation.OP_RETURN];

  for (const op of asm) {
    if (op === OP_RETURN) {
      return [OP_RETURN];
    }
  }

  return asm;
}

function isP2sh(bytes: Buffer): boolean {
  return (
    bytes.length === 23 &&
    bytes[0] == Operation["OP_HASH160"] &&
    bytes[1] == 0x14 && // Operation["OP_PUSHBYTES_20"]
    bytes[22] == Operation["OP_EQUAL"]
  );
}

function isP2pkh(bytes: Buffer): boolean {
  return (
    bytes.length == 25 &&
    bytes[0] == Operation["OP_DUP"] &&
    bytes[1] == Operation["OP_HASH160"] &&
    bytes[2] == 0x14 && // Operation["OP_PUSHBYTES_20"]
    bytes[23] == Operation["OP_EQUALVERIFY"] &&
    bytes[24] == Operation["OP_CHECKSIG"]
  );
}

function isP2pk(bytes: Buffer): boolean {
  if (bytes.length == 67) {
    return (
      bytes[0] == 0x41 && // Operation["OP_PUSHBYTES_65"]
      bytes[66] == Operation["OP_CHECKSIG"]
    );
  } else if (bytes.length == 35) {
    return (
      bytes[0] == 0x21 && // Operation["OP_PUSHBYTES_33"]
      bytes[34] == Operation["OP_CHECKSIG"]
    );
  } else {
    return false;
  }
}

function isReturn(bytes: Buffer): boolean {
  return bytes.includes(Operation["OP_RETURN"]);
}

enum Operation {
  OP_FALSE = 0x00,
  OP_PUSHDATA1 = 0x4c,
  OP_PUSHDATA2 = 0x4d,
  OP_PUSHDATA4 = 0x4e,
  OP_1NEGATE = 0x4f,
  OP_RESERVED = 0x50,
  OP_TRUE = 0x51,
  OP_2 = 0x52,
  OP_3 = 0x53,
  OP_4 = 0x54,
  OP_5 = 0x55,
  OP_6 = 0x56,
  OP_7 = 0x57,
  OP_8 = 0x58,
  OP_9 = 0x59,
  OP_10 = 0x5a,
  OP_11 = 0x5b,
  OP_12 = 0x5c,
  OP_13 = 0x5d,
  OP_14 = 0x5e,
  OP_15 = 0x5f,
  OP_16 = 0x60,
  OP_NOP = 0x61,
  OP_VER = 0x62,
  OP_IF = 0x63,
  OP_NOTIF = 0x64,
  OP_VERIF = 0x65,
  OP_VERNOTIF = 0x66,
  OP_ELSE = 0x67,
  OP_ENDIF = 0x68,
  OP_VERIFY = 0x69,
  OP_RETURN = 0x6a,
  OP_TOALTSTACK = 0x6b,
  OP_FROMALTSTACK = 0x6c,
  OP_2DROP = 0x6d,
  OP_2DUP = 0x6e,
  OP_3DUP = 0x6f,
  OP_2OVER = 0x70,
  OP_2ROT = 0x71,
  OP_2SWAP = 0x72,
  OP_IFDUP = 0x73,
  OP_DEPTH = 0x74,
  OP_DROP = 0x75,
  OP_DUP = 0x76,
  OP_NIP = 0x77,
  OP_OVER = 0x78,
  OP_PICK = 0x79,
  OP_ROLL = 0x7a,
  OP_ROT = 0x7b,
  OP_SWAP = 0x7c,
  OP_TUCK = 0x7d,
  OP_CAT = 0x7e,
  OP_SUBSTR = 0x7f,
  OP_LEFT = 0x80,
  OP_RIGHT = 0x81,
  OP_SIZE = 0x82,
  OP_INVERT = 0x83,
  OP_AND = 0x84,
  OP_OR = 0x85,
  OP_XOR = 0x86,
  OP_EQUAL = 0x87,
  OP_EQUALVERIFY = 0x88,
  OP_RESERVED1 = 0x89,
  OP_RESERVED2 = 0x8a,
  OP_1ADD = 0x8b,
  OP_1SUB = 0x8c,
  OP_2MUL = 0x8d,
  OP_2DIV = 0x8e,
  OP_NEGATE = 0x8f,
  OP_ABS = 0x90,
  OP_NOT = 0x91,
  OP_0NOTEQUAL = 0x92,
  OP_ADD = 0x93,
  OP_SUB = 0x94,
  OP_MUL = 0x95,
  OP_DIV = 0x96,
  OP_MOD = 0x97,
  OP_LSHIFT = 0x98,
  OP_RSHIFT = 0x99,
  OP_BOOLAND = 0x9a,
  OP_BOOLOR = 0x9b,
  OP_NUMEQUAL = 0x9c,
  OP_NUMEQUALVERIFY = 0x9d,
  OP_NUMNOTEQUAL = 0x9e,
  OP_LESSTHAN = 0x9f,
  OP_GREATERTHAN = 0xa0,
  OP_LESSTHANOREQUAL = 0xa1,
  OP_GREATERTHANOREQUAL = 0xa2,
  OP_MIN = 0xa3,
  OP_MAX = 0xa4,
  OP_WITHIN = 0xa5,
  OP_RIPEMD160 = 0xa6,
  OP_SHA1 = 0xa7,
  OP_SHA256 = 0xa8,
  OP_HASH160 = 0xa9,
  OP_HASH256 = 0xaa,
  OP_CODESEPARATOR = 0xab,
  OP_CHECKSIG = 0xac,
  OP_CHECKSIGVERIFY = 0xad,
  OP_CHECKMULTISIG = 0xae,
  OP_CHECKMULTISIGVERIFY = 0xaf,
  OP_NOP1 = 0xb0,
  OP_CHECKLOCKTIMEVERIFY = 0xb1,
  OP_CHECKSEQUENCEVERIFY = 0xb2,
  OP_NOP4 = 0xb3,
  OP_NOP5 = 0xb4,
  OP_NOP6 = 0xb5,
  OP_NOP7 = 0xb6,
  OP_NOP8 = 0xb7,
  OP_NOP9 = 0xb8,
  OP_NOP10 = 0xb9,
  OP_PUBKEYHASH = 0xfd,
  OP_PUBKEY = 0xfe,
  OP_INVALIDOPCODE = 0xff,
}