streamflow-timelock 0.2.1

Timelock crate for Solana programs
Documentation
#!/usr/bin/env python3
# A really lazy parser
import sys
import re
from os.path import join
from subprocess import run

files = ["src/state.rs"]
skips = [
    "InitializeAccounts", "WithdrawAccounts", "CancelAccounts",
    "TransferAccounts"
]
structs = {}


def camel_to_snake(name):
    name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()


def lookup_layout(t, n):
    if t == "u64":
        return f'BufferLayout.blob(8, "{n}"),'
    if t == "Pubkey":
        return f'BufferLayout.blob(32, "{n}"),'

    return None


def generate_buflayout(struct_name):
    for i in structs[struct_name]:
        bl = lookup_layout(i[1], i[0])
        if bl:
            print(f"    {bl}")
            continue
        if i[1] in structs:
            generate_buflayout(i[1])
            continue

        raise Exception(f"Unknown buffer layout for {i[1]})")


def lookup_decoder(t, n):
    if t == "u64":
        return f'"{n}": new BN(raw.{n}),'
    if t == "Pubkey":
        return f'"{n}": new PublicKey(raw.{n}),'

    return None


def generate_decoder(struct_name):
    for i in structs[struct_name]:
        dl = lookup_decoder(i[1], i[0])
        if dl:
            print(f"        {dl}")
            continue
        if i[1] in structs:
            generate_decoder(i[1])
            continue

        raise Exception(f"Unknown decoder for {i[1]}")


def parse_structs(lines):
    found = False
    struct_name = None

    for i in lines:
        if found and not i.strip().startswith(
                "//") and not i.strip().startswith("}"):
            element = i.strip()[4:-1]
            if element.endswith("<'a>"):
                element = element[:-4]

            elem_name, elem_type = element.split(": ")
            structs[struct_name].append((elem_name, elem_type))

        if i.startswith("pub struct"):
            found = True
            struct_name = i.split()[2]
            if struct_name.endswith("<'a>"):
                struct_name = struct_name[:-4]
            structs[struct_name] = []

        if i.startswith("}"):
            found = False


def main():
    output = run(["git", "rev-parse", "--show-toplevel"], capture_output=True)
    toplevel = output.stdout.decode()[:-1]

    print("const BufferLayout = require('buffer-layout');")
    print("const { PublicKey } = require('@solana/web3.js');")
    print("const anchor = require('@project-serum/anchor');")
    print("const { BN } = anchor;\n")

    for src_file in files:
        f = open(join(toplevel, src_file), "r")
        lines = f.readlines()
        f.close()
        parse_structs(lines)

    for i in structs:
        if i in skips:
            continue

        print(f"const {i}Layout = BufferLayout.struct([")
        generate_buflayout(i)
        print(f"]);\n")

        print(f"function decode_{camel_to_snake(i)}(buf) {{")
        print(f"    let raw = {i}Layout.decode(buf);")
        print("    return {")
        generate_decoder(i)
        print("    };\n}\n")

    return 0


if __name__ == "__main__":
    sys.exit(main())