Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@helios-lang/contract-utils

Package Overview
Dependencies
Maintainers
1
Versions
133
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@helios-lang/contract-utils - npm Package Compare versions

Comparing version 0.1.1 to 0.1.2

examples/spending/app.js

9

package.json
{
"name": "@helios-lang/contract-utils",
"version": "0.1.1",
"version": "0.1.2",
"description": "Convenience and type-safety utilities for using Helios validators from within Typescript",

@@ -31,3 +31,10 @@ "main": "src/index.js",

"singleQuote": false
},
"dependencies": {
"@helios-lang/codec-utils": "^0.1.23",
"@helios-lang/compiler-utils": "^0.1.4",
"@helios-lang/ledger": "^0.1.9",
"@helios-lang/type-utils": "^0.1.3",
"@helios-lang/uplc": "^0.1.0"
}
}
#!/usr/bin/env node
import { promises, readFileSync } from "node:fs"
import { dirname, join, resolve } from "node:path"
import { readHeader, translateImportPaths } from "@helios-lang/compiler-utils"
import { TypescriptWriter } from "./codegen/index.js"
import { loadLibrary } from "./lib/index.js"
/**
* @typedef {import("./lib/Lib.js").Lib} Lib
*/
/**
* @typedef {import("./lib/Lib.js").SourceDetails} SourceDetails
*/
/**
* @typedef {import("./lib/Lib.js").ModuleDetails} ModuleDetails
*/
/**
* @typedef {import("./lib/Lib.js").ValidatorDetails} ValidatorDetails
*/
async function main() {

@@ -9,6 +29,143 @@ console.log("hl2ts")

const lib = await loadLibrary()
const filePaths = await listFiles(process.cwd(), ".hl")
const files = readFiles(filePaths)
const sources = preparseFiles(files)
const { modules, validators } = typeCheck(lib, sources)
console.log(lib.version)
const w = new TypescriptWriter()
console.log(modules, validators)
w.writeModules(modules)
w.writeValidators(validators)
const [js, dts] = w.finalize()
console.log(js)
console.log(dts)
}
main()
main()
/**
* @param {string} dir
* @param {string} ext
* @returns {Promise<string[]>}
*/
async function listFiles(dir, ext) {
const entries = await promises.readdir(dir, { withFileTypes: true })
const files = await Promise.all(
entries.map((entry) => {
const res = resolve(dir, entry.name)
if (entry.isDirectory()) {
if (entry.name.endsWith("node_modules")) {
return []
} else {
return listFiles(res, ext)
}
} else {
return res
}
})
)
return files.flat().filter((name) => name.endsWith(ext))
}
/**
* @param {string[]} filePaths
* @returns {{[path: string]: string}}
*/
function readFiles(filePaths) {
return Object.fromEntries(
filePaths.map((f) => {
return [f, readFileSync(f).toString()]
})
)
}
/**
*
* @param {{[path: string]: string}} files
* @returns {{[name: string]: SourceDetails}}
*/
function preparseFiles(files) {
const partialSources = {}
for (let path in files) {
const [purpose, name] = readHeader(files[path])
partialSources[path] = {
name: name,
purpose: purpose,
sourceCode: files[path]
}
}
/**
* @type {{[name: string]: SourceDetails}}
*/
const sources = {}
for (let path in files) {
const sourceCode = translateImportPaths(files[path], (relPath) => {
const absPath = resolve(join(dirname(path), relPath))
const d = partialSources[absPath]
if (!d) {
throw new Error(`'${relPath}' not found`)
}
return d.name
})
sources[partialSources[path].name] = {
...partialSources[path],
sourceCode: sourceCode
}
}
return sources
}
/**
* @param {{[name: string]: SourceDetails}} sources
* @returns {[{[name: string]: SourceDetails}, {[name: string]: SourceDetails}]}
*/
function splitValidatorsAndModules(sources) {
/**
* @type {{[name: string]: SourceDetails}}
*/
const validators = {}
/**
* @type {{[name: string]: SourceDetails}}
*/
const modules = {}
for (let key in sources) {
const v = sources[key]
if (v.purpose == "module") {
modules[key] = v
} else if (
v.purpose == "spending" ||
v.purpose == "minting" ||
v.purpose == "staking"
) {
validators[key] = v
}
}
return [validators, modules]
}
/**
* @param {Lib} lib
* @param {{[name: string]: SourceDetails}} sources
* @returns {{modules: {[name: string]: ModuleDetails}, validators: {[name: string]: ValidatorDetails}}}
*/
function typeCheck(lib, sources) {
const [validators, modules] = splitValidatorsAndModules(sources)
return lib.typeCheck(validators, modules)
}

2

src/lib/index.js

@@ -1,1 +0,1 @@

export { loadLibrary } from "./load.js"
export { loadLibrary } from "./load.js"
/**
* @typedef {{
* version: string
* typeCheck: (validators: {[name: string]: SourceDetails}, modules: {[name: string]: SourceDetails}) => ({
* modules: {[name: string]: ModuleDetails}, validators: {[name: string]: ValidatorDetails}})
* }} Lib

@@ -8,2 +10,16 @@ */

/**
* @typedef {import("../codegen/index.js").TypeSchema} InternalTypeDetails
* @typedef {import("../codegen/index.js").Module} ModuleDetails
* @typedef {import("../codegen/index.js").Validator} ValidatorDetails
*/
/**
* @typedef {{
* name: string
* purpose: string
* sourceCode: string
* }} SourceDetails
*/
/**
* @param {{VERSION: string}} lib

@@ -13,3 +29,3 @@ * @returns {number[]}

export function getVersion(lib) {
return lib.VERSION.split(".").map(v => Number(v))
}
return lib.VERSION.split(".").map((v) => Number(v))
}
/**
* @typedef {import("./Lib.js").Lib} Lib
* @typedef {import("./Lib.js").SourceDetails} SourceDetails
*/
/**
* @typedef {import("../codegen/index.js").Module} ModuleDetails
* @typedef {import("../codegen/index.js").Validator} ValidatorDetails
* @typedef {import("../codegen/index.js").TypeSchema} InternalTypeDetails
*/
/**
* @typedef {{
* [name: string]: string[]
* }} DagDependencies
*/
/**
* @typedef {{
* }} HashType
*/
/**
* @typedef {{
* includes: (m: string) => boolean
* }} IR
*/
/**
* @typedef {{
* name: string
* }} EnumStatement
*/
/**
* @typedef {{
* name: string
* }} StructStatement
*/
/**
* @typedef {StructStatement | EnumStatement | any} Statement
*/
/**
* @typedef {{
* name: {value: string}
* filterDependencies: (all: Module[]) => Module[]
* statements: Statement[]
* }} Module
*/
/**
* @typedef {{
* name: string
* toIR: (ctx: any, extra: Map<string, IR>) => IR
* types: UserTypes
* mainImportedModules: Module[]
* mainModule: Module
* mainArgTypes: DataType[]
* }} Program
*/
/**
* @typedef {{
* typeDetails?: TypeDetails
* }} DataType
*/
/**
* @typedef {{
* type: string
* } | {
* type: "List"
* itemType: TypeSchema
* } | {
* type: "Map"
* keyType: TypeSchema
* valueType: TypeSchema
* } | {
* type: "Option"
* someType: TypeSchema
* } | {
* type: "Struct"
* fieldTypes: NamedTypeSchema[]
* } | {
* type: "Enum"
* variantTypes: {name: string, fieldTypes: NamedTypeSchema[]}[]
* }} TypeSchema
*/
/**
* @typedef {{
* name: string
* } & TypeSchema} NamedTypeSchema
*/
/**
* @typedef {{
* inputType: string
* outputType: string
* internalType: TypeSchema
* }} TypeDetails
*/
/**
* @typedef {{
* }} UserTypes
*/
/**
* @implements {Lib}

@@ -10,3 +115,3 @@ */

/**
* @param {any} lib
* @param {any} lib
*/

@@ -23,2 +128,209 @@ constructor(lib) {

}
}
/**
* @private
* @param {string} purpose
* @returns {HashType}
*/
getValidatorType(purpose) {
switch (purpose) {
case "spending":
return this.lib.ValidatorHashType
case "minting":
return this.lib.MintingPolicyHashType
case "staking":
return this.lib.StakingValidatorHashType
default:
throw new Error("unhandled validator type")
}
}
/**
* @private
* @param {SourceDetails[]} validators
* @param {SourceDetails[]} modules
* @param {{[name: string]: HashType}} validatorTypes
* @returns {Program[]}
*/
createPrograms(validators, modules, validatorTypes) {
const moduleSrcs = modules.map((m) => m.sourceCode)
return validators.map((v) =>
this.lib.Program.newInternal(
v.sourceCode,
moduleSrcs,
validatorTypes,
{
allowPosParams: false,
invertEntryPoint: true
}
)
)
}
/**
* @private
* @param {Program} program
* @param {{[name: string]: HashType}} validatorTypes
* @returns {IR}
*/
toTestIR(program, validatorTypes) {
const extra = new Map()
for (let validatorName in validatorTypes) {
extra.set(
`__helios__scripts__${validatorName}`,
new this.lib.IR(`#`)
)
}
return program.toIR(new this.lib.ToIRContext(false), extra)
}
/**
* @private
* @param {Program[]} validators
* @param {{[name: string]: HashType}} validatorTypes
* @returns {DagDependencies}
*/
buildDagDependencies(validators, validatorTypes) {
/**
* @type {DagDependencies}
*/
const dag = {}
validators.forEach((v) => {
const ir = this.toTestIR(v, validatorTypes)
dag[v.name] = Object.keys(validatorTypes).filter((name) =>
ir.includes(`__helios__scripts__${name}`)
)
})
return dag
}
/**
* @param {{[name: string]: SourceDetails}} validators
* @param {{[name: string]: SourceDetails}} modules
* @returns {{modules: {[name: string]: ModuleDetails}, validators: {[name: string]: ValidatorDetails}}}
*/
typeCheck(validators, modules) {
const validatorTypes = Object.fromEntries(
Object.values(validators).map((v) => [
v.name,
this.getValidatorType(v.purpose)
])
)
// create validator programs
let validatorPrograms = this.createPrograms(
Object.values(validators),
Object.values(modules),
validatorTypes
)
// build dag
const dag = this.buildDagDependencies(validatorPrograms, validatorTypes)
// sort the validators according to the dag, a valid order should exist
// validatorPrograms = this.sortValidators(validatorPrograms, dag)
/**
* @type {{[name: string]: ValidatorDetails}}
*/
const validatorDetails = {}
/**
* @type {{[name: string]: ModuleDetails}}
*/
const moduleDetails = {}
for (let v of validatorPrograms) {
const hashDependencies = dag[v.name]
const allModules = v.mainImportedModules
const moduleDepedencies = v.mainModule
.filterDependencies(allModules)
.map((m) => m.name.value)
const purpose = validators[v.name].purpose
validatorDetails[v.name] = {
name: v.name,
purpose: validators[v.name].purpose,
sourceCode: validators[v.name].sourceCode,
hashDependencies: hashDependencies,
moduleDepedencies: moduleDepedencies,
types: {},
Redeemer: this.getInternalTypeDetails(
v.mainArgTypes[purpose == "spending" ? 1 : 0]
),
Datum:
purpose == "spending"
? this.getInternalTypeDetails(v.mainArgTypes[0])
: undefined
}
for (let m of v.mainImportedModules) {
if (!(m.name.value in moduleDetails)) {
moduleDetails[m.name.value] = {
name: m.name.value,
purpose: "module",
sourceCode: modules[m.name.value].sourceCode,
moduleDepedencies: m
.filterDependencies(allModules)
.map((m) => m.name.value),
types: {} // not yet exported
}
}
}
}
return { modules: moduleDetails, validators: validatorDetails }
}
/**
* @param {TypeSchema} it
* @returns {InternalTypeDetails}
*/
convertInternalType(it) {
if ("itemType" in it) {
return { listItemType: this.convertInternalType(it.itemType) }
} else if ("someType" in it) {
return { optionSomeType: this.convertInternalType(it.someType) }
} else if ("fieldTypes" in it) {
return {
structFieldTypes: it.fieldTypes.map((ft) => ({
name: ft.name,
type: this.convertInternalType(ft)
}))
}
} else if ("keyType" in it) {
return {
mapKeyType: this.convertInternalType(it.keyType),
mapValueType: this.convertInternalType(it.valueType)
}
} else if ("variantTypes" in it) {
return {
enumVariantTypes: it.variantTypes.map((vt) => ({
name: vt.name,
fieldTypes: vt.fieldTypes.map((ft) => ({
name: ft.name,
type: this.convertInternalType(ft)
}))
}))
}
} else {
return { primitiveType: it.type }
}
}
/**
* @param {DataType} dt
* @returns {InternalTypeDetails}
*/
getInternalTypeDetails(dt) {
const it = dt?.typeDetails?.internalType ?? { type: "Any" }
return this.convertInternalType(it)
}
}

@@ -0,1 +1,3 @@

import { existsSync } from "node:fs"
import { dirname, join } from "node:path"
import { getVersion } from "./Lib.js"

@@ -8,6 +10,19 @@ import { Lib_v0_16 } from "./Libg_v0_16.js"

const packageNames = [
"@hyperionbt/helios"
]
/**
* @returns {string}
*/
function findRootDir() {
let dir = process.cwd()
while (dir != "/") {
if (existsSync(join(dir, "package.json"))) {
return dir
} else {
dir = dirname(dir)
}
}
throw new Error("package.json not found")
}
/**

@@ -17,9 +32,15 @@ * @returns {Promise<Lib>}

export async function loadLibrary() {
const rootDir = findRootDir()
const packageNames = ["@hyperionbt/helios/helios.js"]
for (let packageName of packageNames) {
try {
const lib = await eval(`import("${packageName}")`)
const lib = await eval(
`import("${rootDir}/node_modules/${packageName}")`
)
const [major, minor] = getVersion(lib)
switch(major) {
switch (major) {
case 0:

@@ -31,10 +52,13 @@ switch (minor) {

default:
throw new Error(`compiler version ${lib.VERSION} not supported`)
throw new Error(
`compiler version ${lib.VERSION} not supported`
)
}
} catch(_e) {
} catch (_e) {
console.error(_e)
continue
}
}
throw new Error("compiler not installed")
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc