@helios-lang/contract-utils 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ import { Program } from "@hyperionbt/helios"
2
+ import { utils, match_string } from "./unspecialized.js"
3
+
4
+ const modules = [utils, ...]
5
+
6
+ export class App {
7
+ /**
8
+ * @param {typeof utils} specializedUtils
9
+ */
10
+ constructor(specializedUtils) {
11
+ this.program = Program.new(match_string, modules.replace("utils", specializedUtils))
12
+ }
13
+ }
@@ -0,0 +1,18 @@
1
+
2
+ export const utils: {
3
+ $name: string
4
+ $purpose: string
5
+ $sourceCode: string
6
+ $dependencies: []
7
+ }
8
+ export const match_string: {
9
+ $name: string
10
+ $purpose: string
11
+ $sourceCode: string
12
+ $dependencies: [typeof utils]
13
+ $hashDependencies: []
14
+ $dependsOnOwnHash: boolean
15
+ $Redeemer: Cast<string, string>
16
+ $Datum: Cast<{message: string}, {message: string}>
17
+ }
18
+
@@ -0,0 +1,24 @@
1
+
2
+
3
+ export const utils: {
4
+ $name: string
5
+ $purpose: string
6
+ $sourceCode: string
7
+ $dependencies: []
8
+ }
9
+ export const match_string: {
10
+ $name: string
11
+ $purpose: string
12
+ $sourceCode: string
13
+ $dependencies: [typeof utils]
14
+ $hashDependencies: []
15
+ $dependsOnOwnHash: boolean
16
+ $Redeemer: Cast<string, string>
17
+ $Datum: Cast<
18
+ {One: {message: string}} |
19
+ {Two: {code: bigint}},
20
+ {One: {message: string}} |
21
+ {Two: {code: bigint | number | string}}
22
+ >
23
+ }
24
+
@@ -0,0 +1,34 @@
1
+ export const utils = {
2
+ $name: "utils",
3
+ $purpose: "module",
4
+ $sourceCode: "module utils\n\nfunc compare(a: String, b: String) -> Bool {\n a == b\n}",
5
+ $dependencies: [],
6
+ }
7
+ export const match_string = {
8
+ $name: "match_string",
9
+ $purpose: "spending",
10
+ $sourceCode: "spending match_string\n\nimport { compare } from utils\n\nenum Datum {\n One {\n message: String\n }\n\n Two {\n message: String\n }\n}\n\nfunc main(datum: Datum, redeemer: String, _) -> Bool {\n compare(datum.switch{d: One => d.message, d: Two => d.message}, redeemer)\n}",
11
+ $dependencies: [utils],
12
+ $hashDependencies: [],
13
+ $dependsOnOwnHash: false,
14
+ $Redeemer: new Cast({"primitiveType":"String"}),
15
+ $Datum: new Cast({"enumVariantTypes":[{"name":"One","fieldTypes":[{"name":"message","type":{"primitiveType":"String"}}]},{"name":"Two","fieldTypes":[{"name":"message","type":{"primitiveType":"String"}}]}]})
16
+ }
17
+
18
+ export const utils: {
19
+ $name: string
20
+ $purpose: string
21
+ $sourceCode: string
22
+ $dependencies: []
23
+ }
24
+ export const match_string: {
25
+ $name: string
26
+ $purpose: string
27
+ $sourceCode: string
28
+ $dependencies: [typeof utils]
29
+ $hashDependencies: []
30
+ $dependsOnOwnHash: boolean
31
+ $Redeemer: Cast<string, string>
32
+ $Datum: Cast<{One: {message: string}} | {Two: {message: string}}, {One: {message: string}} | {Two: {message: string}}>
33
+ }
34
+
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "spending_example",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {
6
+ "": {
7
+ "name": "spending_example",
8
+ "dependencies": {
9
+ "@helios-lang/contract-utils": "file:../..",
10
+ "@hyperionbt/helios": "^0.16.7"
11
+ }
12
+ },
13
+ "../..": {
14
+ "name": "@helios-lang/contract-utils",
15
+ "version": "0.1.1",
16
+ "license": "BSD-3-Clause",
17
+ "dependencies": {
18
+ "@helios-lang/compiler-utils": "^0.1.2"
19
+ },
20
+ "bin": {
21
+ "hl2ts": "src/hl2ts.js"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.11.24",
25
+ "prettier": "^3.1.0",
26
+ "typescript": "^5.3.2"
27
+ }
28
+ },
29
+ "node_modules/@helios-lang/contract-utils": {
30
+ "resolved": "../..",
31
+ "link": true
32
+ },
33
+ "node_modules/@hyperionbt/helios": {
34
+ "version": "0.16.7",
35
+ "resolved": "https://registry.npmjs.org/@hyperionbt/helios/-/helios-0.16.7.tgz",
36
+ "integrity": "sha512-ysPaF0OCY0NJa1mc+LXERjH71VDNGUbYrrovKUHJv1v+eS1WJhKmxSHWh9sVa6b+sYoXdKwoCR20UQhzCF5jzA=="
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "spending_example",
3
+ "dependencies": {
4
+ "@helios-lang/contract-utils": "file:../..",
5
+ "@hyperionbt/helios": "^0.16.7"
6
+ }
7
+ }
@@ -0,0 +1,6 @@
1
+ export const utils = {
2
+ $name: "utils",
3
+ $purpose: "module",
4
+ $sourceCode: "module utils\n\nfunc compare(a: String, b: String) -> Bool {\n a == b\n}",
5
+ $dependencies: [],
6
+ }
@@ -0,0 +1,17 @@
1
+ spending match_string
2
+
3
+ import { compare } from "./utils.hl"
4
+
5
+ enum Datum {
6
+ One {
7
+ message: String
8
+ }
9
+
10
+ Two {
11
+ code: Int
12
+ }
13
+ }
14
+
15
+ func main(datum: Datum, redeemer: String, _) -> Bool {
16
+ compare(datum.switch{d: One => d.message, d: Two => d.code.show()}, redeemer)
17
+ }
@@ -0,0 +1,18 @@
1
+ import { Cast } from "@helios-lang/contract-utils"
2
+
3
+ export const utils = {
4
+ $name: "utils",
5
+ $purpose: "module",
6
+ $sourceCode: "module utils\n\nfunc compare(a: String, b: String) -> Bool {\n a == b\n}",
7
+ $dependencies: [],
8
+ }
9
+ export const match_string = {
10
+ $name: "match_string",
11
+ $purpose: "spending",
12
+ $sourceCode: "spending match_string\n\nimport { compare } from utils\n\nstruct Datum {\n message: String\n}\n\nfunc main(datum: Datum, redeemer: String, _) -> Bool {\n compare(datum.message, redeemer)\n}",
13
+ $dependencies: [utils],
14
+ $hashDependencies: [],
15
+ $dependsOnOwnHash: false,
16
+ $Redeemer: new Cast({"primitiveType":"String"}),
17
+ $Datum: new Cast({"structFieldTypes":[{"name":"message","type":{"primitiveType":"String"}}]})
18
+ }
@@ -0,0 +1,5 @@
1
+ module utils
2
+
3
+ func compare(a: String, b: String) -> Bool {
4
+ a == b
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helios-lang/contract-utils",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Convenience and type-safety utilities for using Helios validators from within Typescript",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -28,5 +28,12 @@
28
28
  "tabWidth": 4,
29
29
  "semi": false,
30
30
  "singleQuote": false
31
+ },
32
+ "dependencies": {
33
+ "@helios-lang/codec-utils": "^0.1.23",
34
+ "@helios-lang/compiler-utils": "^0.1.4",
35
+ "@helios-lang/ledger": "^0.1.9",
36
+ "@helios-lang/type-utils": "^0.1.3",
37
+ "@helios-lang/uplc": "^0.1.0"
31
38
  }
32
39
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @typedef {import("./TypeSchema.js").TypeSchema} TypeSchema
3
+ */
4
+
5
+ /**
6
+ * @typedef {{
7
+ * name: string
8
+ * purpose: string
9
+ * sourceCode: string
10
+ * moduleDepedencies: string[]
11
+ * types: {[name: string]: TypeSchema}
12
+ * }} Module
13
+ */
14
+
15
+ export const _ = {}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @typedef {{
3
+ * primitiveType: string
4
+ * } | {
5
+ * listItemType: TypeSchema
6
+ * } | {
7
+ * mapKeyType: TypeSchema
8
+ * mapValueType: TypeSchema
9
+ * } | {
10
+ * optionSomeType: TypeSchema
11
+ * } | {
12
+ * structFieldTypes: {
13
+ * name: string
14
+ * type: TypeSchema
15
+ * }[]
16
+ * } | {
17
+ * enumVariantTypes: {
18
+ * name: string,
19
+ * fieldTypes: {
20
+ * name: string
21
+ * type: TypeSchema
22
+ * }[]
23
+ * }[]
24
+ * }} TypeSchema
25
+ */
26
+
27
+ /**
28
+ * @param {TypeSchema} schema
29
+ * @returns {[string, string]} - the first entry is the canonical type, the second is the permissive type
30
+ */
31
+ export function genTypes(schema) {
32
+ if ("primitiveType" in schema) {
33
+ switch (schema.primitiveType) {
34
+ case "Address":
35
+ return ["Address", "Address | string"]
36
+ case "Any":
37
+ return ["never", "any"]
38
+ case "AssetClass":
39
+ return [
40
+ "AssetClass",
41
+ "AssetClass | string | [string | MintingPolicyHash | number[], string | number[]] | {mph: MintingPolicyHash | string | number[], tokenName: string | number[]}"
42
+ ]
43
+ case "Bool":
44
+ return ["boolean", "boolean"]
45
+ case "ByteArray":
46
+ return ["number[]", "number[]"]
47
+ case "Credential":
48
+ return ["Credential", "Credential | PubKeyHash | ValidatorHash"]
49
+ case "Duration":
50
+ return ["bigint", "bigint | number"]
51
+ case "Int":
52
+ return ["bigint", "bigint | number | string"]
53
+ case "MintingPolicyHash":
54
+ return [
55
+ "MintingPolicyHash",
56
+ "MintingPolicyHash | string | number[]"
57
+ ]
58
+ case "PubKey":
59
+ return ["string", "string | number[]"]
60
+ case "PubKeyHash":
61
+ return ["PubKeyHash", "PubKeyHash | string | number[]"]
62
+ case "Real":
63
+ return ["number", "numer"]
64
+ case "StakingCredential":
65
+ return [
66
+ "StakingCredential",
67
+ "StakingCredential | StakingHash | PubKeyHash | StakingValidatorHash"
68
+ ]
69
+ case "StakingHash":
70
+ return [
71
+ "StakingHash",
72
+ "StakingHash | PubKeyHash | StakingValidatorHash"
73
+ ]
74
+ case "StakingValidatorHash":
75
+ return [
76
+ "StakingValidatorHash",
77
+ "StakingValidatorHash | string | number[]"
78
+ ]
79
+ case "String":
80
+ return ["string", "string"]
81
+ case "Time":
82
+ return ["Date", "Data | bigint | number"]
83
+ case "TimeRange":
84
+ return [
85
+ "TimeRange",
86
+ "TimeRange | [Date | number | bigint, Date | number | bigint] | {start?: Date | number | bigint, excludeStart?: boolean, end?: Date | number | bigint, excludeEnd?: boolean}"
87
+ ]
88
+ case "TxId":
89
+ return ["TxId", "TxId | string | number[]"]
90
+ case "TxOutputDatum":
91
+ return [
92
+ "TxOutputDatum | null",
93
+ "TxOutputDatum | null | undefined | DatumHash | UplcData"
94
+ ]
95
+ case "TxOutputId":
96
+ return ["TxOutputId", "TxOutputId | string"]
97
+ case "ValidatorHash":
98
+ return ["ValidatorHash", "ValidatorHash | string | number[]"]
99
+ case "Value":
100
+ return [
101
+ "Value",
102
+ "Value | [MintingPolicyHash | string | number[], [number[] | string, bigint | number | string][]][] | {mph: MintingPolicyHash | string | number[], tokens: {name: number[] | string, qty: bigint | number | string}[]}[]"
103
+ ]
104
+ default:
105
+ throw new Error(
106
+ `unhandled primitive ${schema.primitiveType} in hl2ts`
107
+ )
108
+ }
109
+ } else if ("listItemType" in schema) {
110
+ const [c, p] = genTypes(schema.listItemType)
111
+ return [`${c}[]`, `${p}[]`]
112
+ } else if ("optionSomeType" in schema) {
113
+ const [c, p] = genTypes(schema.optionSomeType)
114
+ return [`${c} | null`, `${p} | null | undefined`]
115
+ } else if ("mapKeyType" in schema) {
116
+ const [ck, pk] = genTypes(schema.mapKeyType)
117
+ const [cv, pv] = genTypes(schema.mapValueType)
118
+
119
+ return [`Map<${ck}, ${cv}>`, `Map<${pk}, ${pv}> | [${pk}, ${pv}][]`]
120
+ } else if ("structFieldTypes" in schema) {
121
+ const fieldTypes = schema.structFieldTypes.map(({ name, type }) => ({
122
+ name: name,
123
+ types: genTypes(type)
124
+ }))
125
+
126
+ return [
127
+ `{${fieldTypes.map(({ name, types: [c, p] }) => `${name}: ${c}`).join(", ")}}`,
128
+ `{${fieldTypes.map(({ name, types: [c, p] }) => `${name}: ${p}`).join(", ")}}`
129
+ ]
130
+ } else if ("enumVariantTypes" in schema) {
131
+ const variantTypes = schema.enumVariantTypes.map(
132
+ ({ name, fieldTypes }) => ({
133
+ name: name,
134
+ types: genTypes({ structFieldTypes: fieldTypes })
135
+ })
136
+ )
137
+
138
+ return [
139
+ variantTypes
140
+ .map(({ name, types: [c, p] }) => `{${name}: ${c}}`)
141
+ .join(" | "),
142
+ variantTypes
143
+ .map(({ name, types: [c, p] }) => `{${name}: ${p}}`)
144
+ .join(" | ")
145
+ ]
146
+ } else {
147
+ throw new Error(`unhandled TypeSchema ${JSON.stringify(schema)}`)
148
+ }
149
+ }
@@ -0,0 +1,176 @@
1
+ import { genTypes } from "./TypeSchema.js"
2
+ import { Writer } from "./Writer.js"
3
+
4
+ /**
5
+ * @typedef {import("./Module.js").Module} Module
6
+ * @typedef {import("./Validator.js").Validator} Validator
7
+ */
8
+
9
+ export class TypescriptWriter {
10
+ constructor() {
11
+ this.wjs = new Writer()
12
+ this.wdts = new Writer()
13
+ }
14
+
15
+ /**
16
+ * @param {string} js
17
+ * @param {string} dts
18
+ * @returns {TypescriptWriter}
19
+ */
20
+ write(js, dts = "") {
21
+ this.wjs.write(js)
22
+ this.wdts.write(dts)
23
+ return this
24
+ }
25
+
26
+ /**
27
+ * @param {string} js
28
+ * @param {string} dts
29
+ * @returns {TypescriptWriter}
30
+ */
31
+ writeLine(js, dts = "") {
32
+ if (js != "") {
33
+ this.wjs.writeLine(js)
34
+ }
35
+
36
+ if (dts != "") {
37
+ this.wdts.writeLine(dts)
38
+ }
39
+
40
+ return this
41
+ }
42
+
43
+ /**
44
+ * @param {Module} m
45
+ */
46
+ writeModule(m) {
47
+ this.write(
48
+ `export const ${m.name} = {
49
+ $name: "${m.name}",
50
+ $purpose: "${m.purpose}",
51
+ $sourceCode: ${JSON.stringify(m.sourceCode)},
52
+ $dependencies: [${m.moduleDepedencies.join(", ")}],
53
+ }
54
+ `,
55
+ `export const ${m.name}: {
56
+ $name: string
57
+ $purpose: string
58
+ $sourceCode: string
59
+ $dependencies: [${m.moduleDepedencies.map((d) => `typeof ${d}`).join(", ")}]
60
+ }
61
+ `
62
+ )
63
+ }
64
+
65
+ /**
66
+ * @param {Validator} v
67
+ */
68
+ writeValidator(v) {
69
+ const redeemerTypes = genTypes(v.Redeemer)
70
+ const datumTypes = v.Datum ? genTypes(v.Datum) : undefined
71
+
72
+ this.write(
73
+ `export const ${v.name} = {
74
+ $name: "${v.name}",
75
+ $purpose: "${v.purpose}",
76
+ $sourceCode: ${JSON.stringify(v.sourceCode)},
77
+ $dependencies: [${v.moduleDepedencies.join(", ")}],
78
+ $hashDependencies: [${v.hashDependencies.filter((d) => d != v.name).join(", ")}],
79
+ $dependsOnOwnHash: ${v.hashDependencies.some((d) => d == v.name)},
80
+ $Redeemer: new Cast(${JSON.stringify(v.Redeemer)}),
81
+ ${datumTypes ? `$Datum: new Cast(${JSON.stringify(v.Datum)})` : ""}
82
+ }
83
+ `,
84
+ `export const ${v.name}: {
85
+ $name: string
86
+ $purpose: string
87
+ $sourceCode: string
88
+ $dependencies: [${v.moduleDepedencies.map((d) => `typeof ${d}`).join(", ")}]
89
+ $hashDependencies: [${v.hashDependencies
90
+ .filter((d) => d != v.name)
91
+ .map((d) => `typeof ${d}`)
92
+ .join(", ")}]
93
+ $dependsOnOwnHash: boolean
94
+ $Redeemer: Cast<${redeemerTypes[0]}, ${redeemerTypes[1]}>
95
+ ${datumTypes ? `$Datum: Cast<${datumTypes[0]}, ${datumTypes[1]}>` : ""}
96
+ }
97
+ `
98
+ )
99
+ }
100
+
101
+ /**
102
+ * @param {{[name: string]: Module}} ms
103
+ */
104
+ writeModules(ms) {
105
+ /**
106
+ * @type {Set<string>}
107
+ */
108
+ const done = new Set()
109
+
110
+ let todo = Object.values(ms)
111
+
112
+ while (todo.length > 0) {
113
+ /**
114
+ * @type {Module[]}
115
+ */
116
+ let todoNext = []
117
+
118
+ for (let i = 0; i < todo.length; i++) {
119
+ const m = todo[i]
120
+
121
+ if (m.moduleDepedencies.every((d) => done.has(d))) {
122
+ this.writeModule(m)
123
+
124
+ done.add(m.name)
125
+ } else {
126
+ todoNext.push(m)
127
+ }
128
+ }
129
+
130
+ todo = todoNext
131
+ }
132
+ }
133
+
134
+ /**
135
+ *
136
+ * @param {{[name: string]: Validator}} validators
137
+ */
138
+ writeValidators(validators) {
139
+ /**
140
+ * @type {Set<string>}
141
+ */
142
+ const done = new Set()
143
+
144
+ let todo = Object.values(validators)
145
+
146
+ while (todo.length > 0) {
147
+ /**
148
+ * @type {Validator[]}
149
+ */
150
+ let todoNext = []
151
+
152
+ for (let i = 0; i < todo.length; i++) {
153
+ const v = todo[i]
154
+
155
+ if (
156
+ v.hashDependencies.every((d) => done.has(d) || d == v.name)
157
+ ) {
158
+ this.writeValidator(v)
159
+
160
+ done.add(v.name)
161
+ } else {
162
+ todoNext.push(v)
163
+ }
164
+ }
165
+
166
+ todo = todoNext
167
+ }
168
+ }
169
+
170
+ /**
171
+ * @returns {[string, string]}
172
+ */
173
+ finalize() {
174
+ return [this.wjs.finalize(), this.wdts.finalize()]
175
+ }
176
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @typedef {import("./TypeSchema.js").TypeSchema} TypeSchema
3
+ */
4
+
5
+ /**
6
+ * @typedef {import("./Module.js").Module} Module
7
+ */
8
+
9
+ /**
10
+ * @typedef {Module & {
11
+ * hashDependencies: string[]
12
+ * Redeemer: TypeSchema
13
+ * Datum?: TypeSchema
14
+ * }} Validator
15
+ */
16
+
17
+ export const _ = {}
@@ -0,0 +1,37 @@
1
+ export class Writer {
2
+ /**
3
+ * @private
4
+ * @readonly
5
+ * @type {string[]}
6
+ */
7
+ parts
8
+
9
+ constructor() {
10
+ this.parts = []
11
+ }
12
+
13
+ /**
14
+ * @param {string} part
15
+ * @returns {Writer}
16
+ */
17
+ write(part) {
18
+ this.parts.push(part)
19
+ return this
20
+ }
21
+
22
+ /**
23
+ * @param {string} line
24
+ * @returns {Writer}
25
+ */
26
+ writeLine(line) {
27
+ this.parts.push(`${line}\n`)
28
+ return this
29
+ }
30
+
31
+ /**
32
+ * @returns {string}
33
+ */
34
+ finalize() {
35
+ return this.parts.join("")
36
+ }
37
+ }
@@ -0,0 +1,14 @@
1
+ export { TypescriptWriter } from "./TypescriptWriter.js"
2
+ export { Writer } from "./Writer.js"
3
+
4
+ /**
5
+ * @typedef {import("./Module.js").Module} Module
6
+ */
7
+
8
+ /**
9
+ * @typedef {import("./TypeSchema.js").TypeSchema} TypeSchema
10
+ */
11
+
12
+ /**
13
+ * @typedef {import("./Validator.js").Validator} Validator
14
+ */