@helios-lang/contract-utils 0.1.20 → 0.1.23
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.
- package/examples/multi-validator/README.md +5 -0
- package/examples/{spending → multi-validator}/contract.js +7 -2
- package/examples/{spending → multi-validator}/index.d.ts +1 -1
- package/examples/{spending → multi-validator}/index.js +3 -3
- package/examples/{spending → multi-validator}/spending.hl +3 -2
- package/package.json +5 -5
- package/src/{runtime → cast}/Cast.js +31 -8
- package/src/cast/index.js +12 -0
- package/src/codegen/LoadedModule.js +9 -0
- package/src/codegen/{TypescriptWriter.js → LoadedScriptsWriter.js} +117 -107
- package/src/codegen/LoadedValidator.js +23 -0
- package/src/codegen/{Module.js → TypeCheckedModule.js} +3 -3
- package/src/codegen/{Validator.js → TypeCheckedValidator.js} +5 -8
- package/src/codegen/TypeSchema.js +4 -0
- package/src/codegen/index.js +5 -4
- package/src/compiler/CompilerLib.js +51 -0
- package/src/{lib/Libg_v0_16.js → compiler/CompilerLib_v0_16.js} +243 -255
- package/src/compiler/index.js +6 -0
- package/src/compiler/ops.js +137 -0
- package/src/context/ContractContext.js +78 -0
- package/src/context/ContractContextBuilder.js +69 -0
- package/src/context/DagCompiler.js +229 -0
- package/src/context/index.js +1 -0
- package/src/hl2ts.js +31 -59
- package/src/index.js +12 -1
- package/types/cast/Cast.d.ts +32 -0
- package/types/cast/Cast.d.ts.map +1 -0
- package/types/cast/PermissiveType.d.ts +3 -0
- package/types/cast/PermissiveType.d.ts.map +1 -0
- package/types/cast/StrictType.d.ts +3 -0
- package/types/cast/StrictType.d.ts.map +1 -0
- package/types/cast/index.d.ts +5 -0
- package/types/cast/index.d.ts.map +1 -0
- package/types/codegen/LoadedModule.d.ts +6 -0
- package/types/codegen/LoadedModule.d.ts.map +1 -0
- package/types/codegen/LoadedScriptsWriter.d.ts +56 -0
- package/types/codegen/LoadedScriptsWriter.d.ts.map +1 -0
- package/types/codegen/LoadedValidator.d.ts +16 -0
- package/types/codegen/LoadedValidator.d.ts.map +1 -0
- package/types/codegen/TypeCheckedModule.d.ts +11 -0
- package/types/codegen/TypeCheckedModule.d.ts.map +1 -0
- package/types/codegen/TypeCheckedValidator.d.ts +8 -0
- package/types/codegen/TypeCheckedValidator.d.ts.map +1 -0
- package/types/codegen/TypeSchema.d.ts +10 -0
- package/types/codegen/TypeSchema.d.ts.map +1 -1
- package/types/codegen/TypescriptWriter.d.ts +4 -4
- package/types/codegen/Validator.d.ts +1 -1
- package/types/codegen/index.d.ts +5 -4
- package/types/codegen/index.d.ts.map +1 -1
- package/types/compiler/CompilerLib.d.ts +45 -0
- package/types/compiler/CompilerLib.d.ts.map +1 -0
- package/types/compiler/CompilerLib_v0_16.d.ts +270 -0
- package/types/compiler/CompilerLib_v0_16.d.ts.map +1 -0
- package/types/compiler/index.d.ts +4 -0
- package/types/compiler/index.d.ts.map +1 -0
- package/types/compiler/ops.d.ts +24 -0
- package/types/compiler/ops.d.ts.map +1 -0
- package/types/context/ContractContext.d.ts +23 -0
- package/types/context/ContractContext.d.ts.map +1 -0
- package/types/context/ContractContextBuilder.d.ts +53 -0
- package/types/context/ContractContextBuilder.d.ts.map +1 -0
- package/types/context/DagCompiler.d.ts +64 -0
- package/types/context/DagCompiler.d.ts.map +1 -0
- package/types/context/index.d.ts +2 -0
- package/types/context/index.d.ts.map +1 -0
- package/types/hl2ts.d.ts +8 -4
- package/types/hl2ts.d.ts.map +1 -1
- package/types/index.d.ts +4 -1
- package/types/index.d.ts.map +1 -1
- package/types/lib/Lib.d.ts +13 -71
- package/types/lib/Lib.d.ts.map +1 -1
- package/types/lib/Libg_v0_16.d.ts +53 -52
- package/types/lib/Libg_v0_16.d.ts.map +1 -1
- package/types/lib/index.d.ts +0 -1
- package/types/lib/index.d.ts.map +1 -1
- package/types/lib/load.d.ts +1 -7
- package/types/lib/load.d.ts.map +1 -1
- package/types/runtime/ContractContext.d.ts +22 -43
- package/types/runtime/ContractContext.d.ts.map +1 -1
- package/types/runtime/ContractContextBuilder.d.ts +15 -123
- package/types/runtime/ContractContextBuilder.d.ts.map +1 -1
- package/types/runtime/DagCompiler.d.ts +64 -0
- package/types/runtime/DagCompiler.d.ts.map +1 -0
- package/types/runtime/PermissiveType.d.ts +1 -1
- package/types/runtime/StrictType.d.ts +1 -1
- package/types/runtime/index.d.ts +0 -2
- package/src/codegen/Writer.js +0 -37
- package/src/lib/Lib.js +0 -56
- package/src/lib/index.js +0 -6
- package/src/lib/load.js +0 -26
- package/src/runtime/ContractContext.js +0 -35
- package/src/runtime/ContractContextBuilder.js +0 -340
- package/src/runtime/index.js +0 -3
- /package/examples/{spending → multi-validator}/minting.hl +0 -0
- /package/examples/{spending → multi-validator}/package-lock.json +0 -0
- /package/examples/{spending → multi-validator}/package.json +0 -0
- /package/examples/{spending → multi-validator}/utils.hl +0 -0
- /package/src/{runtime → cast}/PermissiveType.js +0 -0
- /package/src/{runtime → cast}/StrictType.js +0 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as unsafeLib from "@helios-lang/compiler"
|
|
2
|
+
import {
|
|
3
|
+
translateImportPaths as translateImportPathsInternal,
|
|
4
|
+
readHeader
|
|
5
|
+
} from "@helios-lang/compiler-utils"
|
|
6
|
+
import { CompilerLib_v0_16 } from "./CompilerLib_v0_16.js"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import("./CompilerLib.js").CompilerLib} CompilerLib
|
|
10
|
+
* @typedef {import("./CompilerLib.js").TypeCheckOutput} TypeCheckOutput
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {{VERSION: string}} lib
|
|
15
|
+
* @returns {number[]}
|
|
16
|
+
*/
|
|
17
|
+
function getVersion(lib) {
|
|
18
|
+
return lib.VERSION.split(".").map((v) => Number(v))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The compiler library is passed as an argument instead of loading locally, so any optional configuration of the library can be done externally
|
|
23
|
+
* @returns {CompilerLib}
|
|
24
|
+
*/
|
|
25
|
+
export function loadCompilerLib() {
|
|
26
|
+
const [major, minor] = getVersion(unsafeLib)
|
|
27
|
+
|
|
28
|
+
switch (major) {
|
|
29
|
+
case 0:
|
|
30
|
+
switch (minor) {
|
|
31
|
+
case 16:
|
|
32
|
+
return new CompilerLib_v0_16(unsafeLib)
|
|
33
|
+
}
|
|
34
|
+
default:
|
|
35
|
+
throw new Error(
|
|
36
|
+
`compiler version ${unsafeLib.VERSION} not supported`
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The compiler library is passed as an argument instead of loading locally, so any optional configuration of the library can be done externally
|
|
43
|
+
* @param {CompilerLib} lib
|
|
44
|
+
* @param {{[path: string]: string}} files
|
|
45
|
+
* @param {(current: string, rel: string) => string} relToAbs
|
|
46
|
+
* @returns {TypeCheckOutput}
|
|
47
|
+
*/
|
|
48
|
+
export function typeCheckFiles(lib, files, relToAbs) {
|
|
49
|
+
const scripts = translateImportPaths(files, relToAbs)
|
|
50
|
+
|
|
51
|
+
return typeCheckScripts(lib, scripts)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {CompilerLib} lib
|
|
56
|
+
* @param {string[]} scripts
|
|
57
|
+
* @returns {TypeCheckOutput}
|
|
58
|
+
*/
|
|
59
|
+
export function typeCheckScripts(lib, scripts) {
|
|
60
|
+
const [validators, modules] = splitValidatorsAndModules(scripts)
|
|
61
|
+
|
|
62
|
+
return lib.typeCheck(validators, modules)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Filters out duplicates
|
|
67
|
+
* @param {string[]} scripts
|
|
68
|
+
* @returns {[string[], string[]]} - [validators, modules]
|
|
69
|
+
*/
|
|
70
|
+
function splitValidatorsAndModules(scripts) {
|
|
71
|
+
/**
|
|
72
|
+
* @type {Map<string, string>}
|
|
73
|
+
*/
|
|
74
|
+
const validators = new Map()
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @type {Map<string, string>}
|
|
78
|
+
*/
|
|
79
|
+
const modules = new Map()
|
|
80
|
+
|
|
81
|
+
scripts.forEach((s) => {
|
|
82
|
+
const [purpose, name] = readHeader(s)
|
|
83
|
+
|
|
84
|
+
switch (purpose) {
|
|
85
|
+
case "module":
|
|
86
|
+
modules.set(name, s)
|
|
87
|
+
break
|
|
88
|
+
case "minting":
|
|
89
|
+
case "spending":
|
|
90
|
+
case "certifying":
|
|
91
|
+
case "rewarding":
|
|
92
|
+
case "staking":
|
|
93
|
+
validators.set(name, s)
|
|
94
|
+
break
|
|
95
|
+
default:
|
|
96
|
+
throw new Error(
|
|
97
|
+
`unhandled script purpose ${purpose} in script ${name}`
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
return [Array.from(validators.values()), Array.from(modules.values())]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
*
|
|
107
|
+
* @param {{[path: string]: string}} files
|
|
108
|
+
* @param {(current: string, rel: string) => string} relToAbs
|
|
109
|
+
* @returns {string[]}
|
|
110
|
+
*/
|
|
111
|
+
function translateImportPaths(files, relToAbs) {
|
|
112
|
+
const partialSources = {}
|
|
113
|
+
|
|
114
|
+
for (let path in files) {
|
|
115
|
+
const [purpose, name] = readHeader(files[path])
|
|
116
|
+
|
|
117
|
+
partialSources[path] = {
|
|
118
|
+
name: name,
|
|
119
|
+
purpose: purpose,
|
|
120
|
+
sourceCode: files[path]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return Object.entries(files).map(([path, file]) =>
|
|
125
|
+
translateImportPathsInternal(file, (relPath) => {
|
|
126
|
+
const absPath = relToAbs(path, relPath)
|
|
127
|
+
|
|
128
|
+
const d = partialSources[absPath] ?? partialSources[absPath + ".hl"]
|
|
129
|
+
|
|
130
|
+
if (!d) {
|
|
131
|
+
throw new Error(`'${relPath}' not found`)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return d.name
|
|
135
|
+
})
|
|
136
|
+
)
|
|
137
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StakingValidatorHash,
|
|
3
|
+
ValidatorHash,
|
|
4
|
+
MintingPolicyHash
|
|
5
|
+
} from "@helios-lang/ledger"
|
|
6
|
+
import { Cast } from "../cast/index.js"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import("../codegen/index.js").LoadedValidator} LoadedValidator
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @template TRedeemerStrict
|
|
14
|
+
* @template TRedeemerPermissive
|
|
15
|
+
* @typedef {import("@helios-lang/ledger").MintingContext<TRedeemerStrict, TRedeemerPermissive>} MintingContext
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @template TDatumStrict
|
|
20
|
+
* @template TDatumPermissive
|
|
21
|
+
* @template TRedeemerStrict
|
|
22
|
+
* @template TRedeemerPermissive
|
|
23
|
+
* @typedef {import("@helios-lang/ledger").SpendingContext<TDatumStrict, TDatumPermissive, TRedeemerStrict, TRedeemerPermissive>} SpendingContext
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @template TRedeemerStrict
|
|
28
|
+
* @template TRedeemerPermissive
|
|
29
|
+
* @typedef {import("@helios-lang/ledger").StakingContext<TRedeemerStrict, TRedeemerPermissive>} StakingContext
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @template {Cast} C
|
|
34
|
+
* @typedef {import("../cast/index.js").PermissiveType<C>} PermissiveType
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @template {Cast} C
|
|
39
|
+
* @typedef {import("../cast/index.js").StrictType<C>} StrictType
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {(
|
|
44
|
+
* ValidatorHash<SpendingContext<any, any, any, any>> |
|
|
45
|
+
* MintingPolicyHash<MintingContext<any, any>> |
|
|
46
|
+
* StakingValidatorHash<StakingContext<any, any>>
|
|
47
|
+
* )} AnyContractValidatorHash
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @template {LoadedValidator} V
|
|
52
|
+
* @typedef {V extends {"$purpose": "spending", "$Datum": Cast} ? ValidatorHash<
|
|
53
|
+
* SpendingContext<
|
|
54
|
+
* StrictType<V["$Datum"]>,
|
|
55
|
+
* PermissiveType<V["$Datum"]>,
|
|
56
|
+
* StrictType<V["$Redeemer"]>,
|
|
57
|
+
* PermissiveType<V["$Redeemer"]>
|
|
58
|
+
* >
|
|
59
|
+
* > :
|
|
60
|
+
* V extends {"$purpose": "minting"} ? MintingPolicyHash<
|
|
61
|
+
* MintingContext<
|
|
62
|
+
* StrictType<V["$Redeemer"]>,
|
|
63
|
+
* PermissiveType<V["$Redeemer"]>
|
|
64
|
+
* >
|
|
65
|
+
* > :
|
|
66
|
+
* V extends {"$purpose": ("certifying" | "rewarding")} ? StakingValidatorHash<
|
|
67
|
+
* StakingContext<
|
|
68
|
+
* StrictType<V["$Redeemer"]>,
|
|
69
|
+
* PermissiveType<V["$Redeemer"]>
|
|
70
|
+
* >
|
|
71
|
+
* > : never
|
|
72
|
+
* } ContractValidatorHash
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @template {{[name: string]: LoadedValidator}} T
|
|
77
|
+
* @typedef {{[K in keyof T]: ContractValidatorHash<T[K]>}} ContractContext
|
|
78
|
+
*/
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { None } from "@helios-lang/type-utils"
|
|
2
|
+
import { loadCompilerLib } from "../compiler/index.js"
|
|
3
|
+
import { DagCompiler } from "./DagCompiler.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import("../codegen/LoadedModule.js").LoadedModule} LoadedModule
|
|
7
|
+
* @typedef {import("../codegen/LoadedValidator.js").LoadedValidator} LoadedValidator
|
|
8
|
+
* @typedef {import("../compiler/index.js").CompilerLib} CompilerLib
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @template {{[name: string]: LoadedValidator}} T
|
|
13
|
+
* @typedef {import("./ContractContext.js").ContractContext<T>} ContractContext
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @template {{[name: string]: LoadedValidator}} T
|
|
18
|
+
*/
|
|
19
|
+
export class ContractContextBuilder {
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
* @readonly
|
|
23
|
+
* @type {T}
|
|
24
|
+
*/
|
|
25
|
+
validators
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @private
|
|
29
|
+
* @param {T} validators
|
|
30
|
+
*/
|
|
31
|
+
constructor(validators) {
|
|
32
|
+
this.validators = validators
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @returns {ContractContextBuilder<{}>}
|
|
37
|
+
*/
|
|
38
|
+
static new() {
|
|
39
|
+
return new ContractContextBuilder({})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @template {LoadedValidator} V
|
|
44
|
+
* @param {V} validator
|
|
45
|
+
* @returns {ContractContextBuilder<T & {
|
|
46
|
+
* [K in V["$name"]]: V
|
|
47
|
+
* }>}
|
|
48
|
+
*/
|
|
49
|
+
with(validator) {
|
|
50
|
+
return new ContractContextBuilder({
|
|
51
|
+
...this.validators,
|
|
52
|
+
[validator.$name]: validator
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {Option<{[name: string]: string}>} expectedHashes
|
|
58
|
+
* @returns {ContractContext<T>}
|
|
59
|
+
*/
|
|
60
|
+
build(expectedHashes = None) {
|
|
61
|
+
const lib = loadCompilerLib()
|
|
62
|
+
|
|
63
|
+
const dagCompiler = new DagCompiler(lib)
|
|
64
|
+
|
|
65
|
+
return /** @type {any} */ (
|
|
66
|
+
dagCompiler.build(Object.values(this.validators), expectedHashes)
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { bytesToHex } from "@helios-lang/codec-utils"
|
|
2
|
+
import {
|
|
3
|
+
MintingPolicyHash,
|
|
4
|
+
StakingValidatorHash,
|
|
5
|
+
ValidatorHash
|
|
6
|
+
} from "@helios-lang/ledger"
|
|
7
|
+
import { None } from "@helios-lang/type-utils"
|
|
8
|
+
import { UplcProgramV2 } from "@helios-lang/uplc"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {import("../codegen/LoadedValidator.js").LoadedValidator} LoadedValidator
|
|
12
|
+
* @typedef {import("../compiler/index.js").CompilerLib} CompilerLib
|
|
13
|
+
* @typedef {import("./ContractContext.js").AnyContractValidatorHash} AnyContractValidatorHash
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Compiles a set of validators that depend on eachothers hashes (forming a Directed Acyclical Graph)
|
|
18
|
+
*/
|
|
19
|
+
export class DagCompiler {
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
* @readonly
|
|
23
|
+
* @type {CompilerLib}
|
|
24
|
+
*/
|
|
25
|
+
lib
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @private
|
|
29
|
+
* @readonly
|
|
30
|
+
* @type {{[name: string]: AnyContractValidatorHash}}
|
|
31
|
+
*/
|
|
32
|
+
cache
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {CompilerLib} lib
|
|
36
|
+
*/
|
|
37
|
+
constructor(lib) {
|
|
38
|
+
this.lib = lib
|
|
39
|
+
this.cache = {}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {LoadedValidator[]} validators
|
|
44
|
+
* @param {Option<{[name: string]: string}>} expectedHashes
|
|
45
|
+
* @returns {{[name: string]: AnyContractValidatorHash}}
|
|
46
|
+
*/
|
|
47
|
+
build(validators, expectedHashes = None) {
|
|
48
|
+
const hashTypes = this.getHashTypes(validators)
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* `buildValidator()` is a closure instead of a member method of DagCompiler
|
|
52
|
+
* because this way we have easy access to `hashTypes` and `expectedHashes`
|
|
53
|
+
* @param {LoadedValidator} validator
|
|
54
|
+
*/
|
|
55
|
+
const buildValidator = (validator) => {
|
|
56
|
+
const name = validator.$name
|
|
57
|
+
const sourceCode = validator.$sourceCode
|
|
58
|
+
|
|
59
|
+
// if already built before, return immediately
|
|
60
|
+
if (name in this.cache) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// make sure all the hash dependencies are built first
|
|
65
|
+
validator.$hashDependencies.forEach((v) => buildValidator(v))
|
|
66
|
+
|
|
67
|
+
// get the dependencies
|
|
68
|
+
const hashDeps = this.getHashDependencies(validator)
|
|
69
|
+
const moduleDeps = getModuleDependencies(validator)
|
|
70
|
+
|
|
71
|
+
// optimized compilation
|
|
72
|
+
const { cborHex: optimizedCborHex, prettyIR } = this.lib.compile(
|
|
73
|
+
sourceCode,
|
|
74
|
+
moduleDeps,
|
|
75
|
+
{
|
|
76
|
+
optimize: true,
|
|
77
|
+
hashDependencies: hashDeps,
|
|
78
|
+
allValidatorHashTypes: hashTypes,
|
|
79
|
+
dependsOnOwnHash: validator.$dependsOnOwnHash
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
const optimizedProgram = UplcProgramV2.fromCbor(optimizedCborHex)
|
|
84
|
+
|
|
85
|
+
// calculate the hash
|
|
86
|
+
const ownHash = bytesToHex(optimizedProgram.hash())
|
|
87
|
+
|
|
88
|
+
// optionally assert the own hash is equal to a given hash
|
|
89
|
+
if (expectedHashes && name in expectedHashes) {
|
|
90
|
+
if (expectedHashes[name] != ownHash) {
|
|
91
|
+
console.log(prettyIR)
|
|
92
|
+
|
|
93
|
+
throw new Error(
|
|
94
|
+
`expected hash ${expectedHashes[name]} for validator ${name}, got ${ownHash}`
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// unoptimized compilation (so traces are untouched)
|
|
100
|
+
const { cborHex: unoptimizedCborHex } = this.lib.compile(
|
|
101
|
+
validator.$sourceCode,
|
|
102
|
+
Array.from(moduleDeps.values()),
|
|
103
|
+
{
|
|
104
|
+
optimize: false,
|
|
105
|
+
hashDependencies: hashDeps,
|
|
106
|
+
allValidatorHashTypes: hashTypes,
|
|
107
|
+
ownHash: validator.$dependsOnOwnHash ? ownHash : undefined
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
const unoptimizedProgram =
|
|
112
|
+
UplcProgramV2.fromCbor(unoptimizedCborHex)
|
|
113
|
+
|
|
114
|
+
// add result to cache (unoptimizedProgram is attached to optimizedProgram)
|
|
115
|
+
this.addToCache(
|
|
116
|
+
validator,
|
|
117
|
+
optimizedProgram.withAlt(unoptimizedProgram),
|
|
118
|
+
ownHash
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
validators.forEach((v) => buildValidator(v))
|
|
123
|
+
|
|
124
|
+
return this.cache
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @private
|
|
129
|
+
* @param {LoadedValidator} validator
|
|
130
|
+
* @param {UplcProgramV2} program
|
|
131
|
+
* @param {string} hash - although this can be derived from `program`, reuse this to save some effort
|
|
132
|
+
*/
|
|
133
|
+
addToCache(validator, program, hash) {
|
|
134
|
+
const name = validator.$name
|
|
135
|
+
const redeemer = validator.$Redeemer
|
|
136
|
+
|
|
137
|
+
switch (validator.$purpose) {
|
|
138
|
+
case "spending":
|
|
139
|
+
this.cache[name] = new ValidatorHash(hash, {
|
|
140
|
+
program,
|
|
141
|
+
redeemer,
|
|
142
|
+
datum: validator.$Datum
|
|
143
|
+
})
|
|
144
|
+
break
|
|
145
|
+
case "minting":
|
|
146
|
+
this.cache[name] = new MintingPolicyHash(hash, {
|
|
147
|
+
program,
|
|
148
|
+
redeemer
|
|
149
|
+
})
|
|
150
|
+
break
|
|
151
|
+
case "certifying":
|
|
152
|
+
case "rewarding":
|
|
153
|
+
case "staking":
|
|
154
|
+
this.cache[name] = new StakingValidatorHash(hash, {
|
|
155
|
+
program,
|
|
156
|
+
redeemer
|
|
157
|
+
})
|
|
158
|
+
break
|
|
159
|
+
default:
|
|
160
|
+
throw new Error("unhandled purpose")
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @private
|
|
166
|
+
* @param {LoadedValidator} validator
|
|
167
|
+
* @returns {{[name: string]: string}} - TODO: do we really need the purpose?
|
|
168
|
+
*/
|
|
169
|
+
getHashDependencies(validator) {
|
|
170
|
+
/**
|
|
171
|
+
* @type {{[name: string]: string}}
|
|
172
|
+
*/
|
|
173
|
+
const deps = {}
|
|
174
|
+
|
|
175
|
+
validator.$hashDependencies.forEach((dep) => {
|
|
176
|
+
const k = dep.$name
|
|
177
|
+
const v = this.cache[k]
|
|
178
|
+
|
|
179
|
+
if (!v) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`${k} should've been built before ${validator.$name}`
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
deps[k] = v.toHex()
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
return deps
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @private
|
|
193
|
+
* @param {LoadedValidator[]} validators
|
|
194
|
+
* @returns {{[name: string]: any}}
|
|
195
|
+
*/
|
|
196
|
+
getHashTypes(validators) {
|
|
197
|
+
return Object.fromEntries(
|
|
198
|
+
validators.map((v) => {
|
|
199
|
+
return [v.$name, this.lib.getScriptHashType(v.$purpose)]
|
|
200
|
+
})
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @param {LoadedValidator} validator
|
|
207
|
+
* @returns {string[]}
|
|
208
|
+
*/
|
|
209
|
+
export function getModuleDependencies(validator) {
|
|
210
|
+
/**
|
|
211
|
+
* @type {Map<string, string>}
|
|
212
|
+
*/
|
|
213
|
+
const deps = new Map()
|
|
214
|
+
|
|
215
|
+
let stack = validator.$dependencies.slice()
|
|
216
|
+
let m = stack.pop()
|
|
217
|
+
|
|
218
|
+
while (m) {
|
|
219
|
+
if (!deps.has(m.$name)) {
|
|
220
|
+
deps.set(m.$name, m.$sourceCode)
|
|
221
|
+
|
|
222
|
+
stack = stack.concat(m.$dependencies)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
m = stack.pop()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return Array.from(deps.values())
|
|
229
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ContractContextBuilder } from "./ContractContextBuilder.js"
|
package/src/hl2ts.js
CHANGED
|
@@ -3,40 +3,54 @@
|
|
|
3
3
|
import { promises, readFileSync, writeFileSync } from "node:fs"
|
|
4
4
|
import { dirname, join, resolve } from "node:path"
|
|
5
5
|
import { readHeader, translateImportPaths } from "@helios-lang/compiler-utils"
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { LoadedScriptsWriter } from "./codegen/index.js"
|
|
7
|
+
import { loadCompilerLib } from "./compiler/index.js"
|
|
8
|
+
import { typeCheckFiles, typeCheckScripts } from "./compiler/ops.js"
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
* @typedef {import("./
|
|
11
|
-
* @typedef {import("./
|
|
12
|
-
* @typedef {import("./
|
|
13
|
-
|
|
11
|
+
* @typedef {import("./compiler/CompilerLib.js").CompilerLib} CompilerLib
|
|
12
|
+
* @typedef {import("./compiler/CompilerLib.js").TypeCheckedModule} ModuleDetails
|
|
13
|
+
* @typedef {import("./compiler/CompilerLib.js").TypeCheckedValidator} ValidatorDetails
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {{
|
|
18
|
+
* name: string
|
|
19
|
+
* purpose: string
|
|
20
|
+
* sourceCode: string
|
|
21
|
+
* }} SourceDetails
|
|
14
22
|
*/
|
|
15
23
|
|
|
16
24
|
async function main() {
|
|
17
|
-
|
|
25
|
+
const lib = loadCompilerLib()
|
|
18
26
|
|
|
19
27
|
const { outDir } = parseArgs(process.argv)
|
|
20
28
|
|
|
21
|
-
const lib = await loadLibrary()
|
|
22
29
|
const filePaths = await listFiles(process.cwd(), ".hl")
|
|
23
30
|
const files = readFiles(filePaths)
|
|
24
|
-
const sources = preparseFiles(files)
|
|
25
|
-
const { modules, validators } = typeCheck(lib, sources)
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
console.log(`hl2ts using Helios compiler v${lib.version}`)
|
|
33
|
+
console.log(` Transpiling ${Object.keys(files).length} inputs:`)
|
|
34
|
+
filePaths.forEach((p) => console.log(` ${p}`))
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
const { modules, validators } = typeCheckFiles(lib, files, (current, rel) =>
|
|
37
|
+
resolve(join(dirname(current), rel))
|
|
38
|
+
)
|
|
32
39
|
|
|
33
|
-
const [js, dts] =
|
|
40
|
+
const [js, dts] = LoadedScriptsWriter.new()
|
|
41
|
+
.writeModules(modules)
|
|
42
|
+
.writeValidators(validators)
|
|
43
|
+
.finalize()
|
|
34
44
|
|
|
35
45
|
const jsPath = join(outDir, "index.js")
|
|
36
46
|
const dtsPath = join(outDir, "index.d.ts")
|
|
37
47
|
|
|
38
48
|
writeFileSync(jsPath, js)
|
|
39
49
|
writeFileSync(dtsPath, dts)
|
|
50
|
+
|
|
51
|
+
console.log(` Output:`)
|
|
52
|
+
console.log(` ${jsPath}`)
|
|
53
|
+
console.log(` ${dtsPath}`)
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
main()
|
|
@@ -100,7 +114,7 @@ function readFiles(filePaths) {
|
|
|
100
114
|
/**
|
|
101
115
|
*
|
|
102
116
|
* @param {{[path: string]: string}} files
|
|
103
|
-
* @returns {
|
|
117
|
+
* @returns {string[]}
|
|
104
118
|
*/
|
|
105
119
|
function preparseFiles(files) {
|
|
106
120
|
const partialSources = {}
|
|
@@ -139,47 +153,5 @@ function preparseFiles(files) {
|
|
|
139
153
|
}
|
|
140
154
|
}
|
|
141
155
|
|
|
142
|
-
return sources
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* @param {{[name: string]: SourceDetails}} sources
|
|
147
|
-
* @returns {[{[name: string]: SourceDetails}, {[name: string]: SourceDetails}]}
|
|
148
|
-
*/
|
|
149
|
-
function splitValidatorsAndModules(sources) {
|
|
150
|
-
/**
|
|
151
|
-
* @type {{[name: string]: SourceDetails}}
|
|
152
|
-
*/
|
|
153
|
-
const validators = {}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* @type {{[name: string]: SourceDetails}}
|
|
157
|
-
*/
|
|
158
|
-
const modules = {}
|
|
159
|
-
|
|
160
|
-
for (let key in sources) {
|
|
161
|
-
const v = sources[key]
|
|
162
|
-
if (v.purpose == "module") {
|
|
163
|
-
modules[key] = v
|
|
164
|
-
} else if (
|
|
165
|
-
v.purpose == "spending" ||
|
|
166
|
-
v.purpose == "minting" ||
|
|
167
|
-
v.purpose == "staking"
|
|
168
|
-
) {
|
|
169
|
-
validators[key] = v
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return [validators, modules]
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* @param {Lib} lib
|
|
178
|
-
* @param {{[name: string]: SourceDetails}} sources
|
|
179
|
-
* @returns {{modules: {[name: string]: ModuleDetails}, validators: {[name: string]: ValidatorDetails}}}
|
|
180
|
-
*/
|
|
181
|
-
function typeCheck(lib, sources) {
|
|
182
|
-
const [validators, modules] = splitValidatorsAndModules(sources)
|
|
183
|
-
|
|
184
|
-
return lib.typeCheck(validators, modules)
|
|
156
|
+
return Object.values(sources).map((s) => s.sourceCode)
|
|
185
157
|
}
|
package/src/index.js
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
export { Cast
|
|
1
|
+
export { Cast } from "./cast/index.js"
|
|
2
|
+
export { ContractContextBuilder } from "./context/index.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @template {import("./cast/index.js").Cast} C
|
|
6
|
+
* @typedef {import("./cast/index.js").StrictType<C>} StrictType
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @template {import("./cast/index.js").Cast} C
|
|
11
|
+
* @typedef {import("./cast/index.js").PermissiveType<C>} PermissiveType
|
|
12
|
+
*/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("@helios-lang/uplc").UplcData} UplcData
|
|
3
|
+
* @typedef {import("../codegen/index.js").TypeSchema} TypeSchema
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @template [TStrict=any]
|
|
7
|
+
* @template [TPermissive=any]
|
|
8
|
+
*/
|
|
9
|
+
export class Cast<TStrict = any, TPermissive = any> {
|
|
10
|
+
/**
|
|
11
|
+
* @param {TypeSchema} schema
|
|
12
|
+
*/
|
|
13
|
+
constructor(schema: TypeSchema);
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {TypeSchema}
|
|
17
|
+
*/
|
|
18
|
+
readonly schema: TypeSchema;
|
|
19
|
+
/**
|
|
20
|
+
* @param {UplcData} data
|
|
21
|
+
* @returns {TStrict}
|
|
22
|
+
*/
|
|
23
|
+
fromUplcData(data: UplcData): TStrict;
|
|
24
|
+
/**
|
|
25
|
+
* @param {TPermissive} x
|
|
26
|
+
* @returns {UplcData}
|
|
27
|
+
*/
|
|
28
|
+
toUplcData(x: TPermissive): UplcData;
|
|
29
|
+
}
|
|
30
|
+
export type UplcData = import("@helios-lang/uplc").UplcData;
|
|
31
|
+
export type TypeSchema = import("../codegen/index.js").TypeSchema;
|
|
32
|
+
//# sourceMappingURL=Cast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cast.d.ts","sourceRoot":"","sources":["../../src/cast/Cast.js"],"names":[],"mappings":"AAiCA;;;GAGG;AAEH;;;GAGG;AACH;IAOI;;OAEG;IACH,oBAFW,UAAU,EAIpB;IAXD;;;OAGG;IACH,iBAFU,UAAU,CAEd;IASN;;;OAGG;IACH,mBAHW,QAAQ,GACN,OAAO,CAInB;IAED;;;OAGG;IACH,cAHW,WAAW,GACT,QAAQ,CAIpB;CACJ;uBArCY,OAAO,mBAAmB,EAAE,QAAQ;yBACpC,OAAO,qBAAqB,EAAE,UAAU"}
|