@helios-lang/contract-utils 0.1.1 → 0.1.6

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,293 @@
1
+ import { decodeUtf8, encodeUtf8 } from "@helios-lang/codec-utils"
2
+ import { REAL_PRECISION } from "@helios-lang/compiler-utils"
3
+ import { None } from "@helios-lang/type-utils"
4
+ import {
5
+ Address,
6
+ AssetClass,
7
+ Credential,
8
+ DatumHash,
9
+ DCert,
10
+ MintingPolicyHash,
11
+ PubKeyHash,
12
+ ScriptHash,
13
+ StakingCredential,
14
+ StakingHash,
15
+ StakingValidatorHash,
16
+ TimeRange,
17
+ TxId,
18
+ TxOutputDatum,
19
+ TxOutputId,
20
+ ValidatorHash,
21
+ Value
22
+ } from "@helios-lang/ledger"
23
+ import {
24
+ ByteArrayData,
25
+ ConstrData,
26
+ IntData,
27
+ ListData,
28
+ MapData,
29
+ decodeOptionData,
30
+ encodeOptionData
31
+ } from "@helios-lang/uplc"
32
+
33
+ /**
34
+ * @typedef {import("@helios-lang/uplc").UplcData} UplcData
35
+ * @typedef {import("../codegen/index.js").TypeSchema} TypeSchema
36
+ */
37
+
38
+ /**
39
+ * @template TStrict
40
+ * @template TPermissive
41
+ */
42
+ export class Cast {
43
+ /**
44
+ * @readonly
45
+ * @type {TypeSchema}
46
+ */
47
+ schema
48
+
49
+ /**
50
+ * @param {TypeSchema} schema
51
+ */
52
+ constructor(schema) {
53
+ this.schema = schema
54
+ }
55
+
56
+ /**
57
+ * @param {UplcData} data
58
+ * @returns {TStrict}
59
+ */
60
+ fromUplc(data) {
61
+ return uplcToSchema(this.schema, data)
62
+ }
63
+
64
+ /**
65
+ * @param {TPermissive} x
66
+ * @returns {UplcData}
67
+ */
68
+ toUplc(x) {
69
+ return schemaToUplc(this.schema, x)
70
+ }
71
+ }
72
+
73
+ /**
74
+ * @param {TypeSchema} schema
75
+ * @param {any} x
76
+ * @returns {UplcData}
77
+ */
78
+ function schemaToUplc(schema, x) {
79
+ if ("primitiveType" in schema) {
80
+ switch (schema.primitiveType) {
81
+ case "Address":
82
+ return Address.fromAlike(x).toUplcData()
83
+ case "Any":
84
+ return new IntData(0n)
85
+ case "AssetClass":
86
+ return AssetClass.fromAlike(x).toUplcData()
87
+ case "Bool":
88
+ return new ConstrData(x ? 1 : 0, [])
89
+ case "ByteArray":
90
+ return new ByteArrayData(x)
91
+ case "Credential":
92
+ case "PaymentCredential":
93
+ return Credential.fromAlike(x).toUplcData()
94
+ case "Data":
95
+ return x
96
+ case "DatumHash":
97
+ return DatumHash.fromAlike(x).toUplcData()
98
+ case "DCert":
99
+ return x.toUplcData()
100
+ case "MintingPolicyHash":
101
+ return MintingPolicyHash.fromAlike(x).toUplcData()
102
+ case "PubKeyHash":
103
+ return PubKeyHash.fromAlike(x).toUplcData()
104
+ case "Real":
105
+ return new IntData(Math.round(x * Math.pow(10, REAL_PRECISION)))
106
+ case "ScriptHash":
107
+ return ScriptHash.fromAlike(x).toUplcData()
108
+ case "StakingCredential":
109
+ return StakingCredential.fromAlike(x).toUplcData()
110
+ case "StakingHash":
111
+ return StakingHash.fromAlike(x).toUplcData()
112
+ case "String":
113
+ return new ByteArrayData(encodeUtf8(x))
114
+ case "Time":
115
+ // milliseconds since 1 jan 1970
116
+ const ms = x instanceof Date ? x.getTime() : x
117
+ return new IntData(ms)
118
+ case "TimeRange":
119
+ return TimeRange.fromAlike(x).toUplcData()
120
+ case "TxId":
121
+ return TxId.fromAlike(x).toUplcData()
122
+ case "TxOutputDatum":
123
+ return x
124
+ ? TxOutputDatum.fromAlike(x)?.toUplcData() ??
125
+ new ConstrData(0, [])
126
+ : new ConstrData(0, [])
127
+ case "TxOutputId":
128
+ return TxOutputId.fromAlike(x).toUplcData()
129
+ case "ValidatorHash":
130
+ return ValidatorHash.fromAlike(x).toUplcData()
131
+ case "Value":
132
+ return Value.fromAlike(x).toUplcData()
133
+ default:
134
+ throw new Error("not yet implemented")
135
+ }
136
+ } else if ("listItemType" in schema) {
137
+ return new ListData(x.map((x) => schemaToUplc(schema.listItemType, x)))
138
+ } else if ("mapKeyType" in schema) {
139
+ const entries = x instanceof Map ? x.entries() : x
140
+ return new MapData(
141
+ entries.map(([k, v]) => [
142
+ schemaToUplc(schema.mapKeyType, k),
143
+ schemaToUplc(schema.mapValueType, v)
144
+ ])
145
+ )
146
+ } else if ("optionSomeType" in schema) {
147
+ return encodeOptionData(
148
+ x ? schemaToUplc(schema.optionSomeType, x) : None
149
+ )
150
+ } else if ("structFieldTypes" in schema) {
151
+ // TODO: Cip-68 support
152
+ if (schema.structFieldTypes.length == 1) {
153
+ return schemaToUplc(
154
+ schema.structFieldTypes[0].type,
155
+ x[schema.structFieldTypes[0].name]
156
+ )
157
+ } else {
158
+ return new ListData(
159
+ schema.structFieldTypes.map(({ name, type }) =>
160
+ schemaToUplc(type, x[name])
161
+ )
162
+ )
163
+ }
164
+ } else if ("enumVariantTypes") {
165
+ const variantName = Object.keys(x)[0]
166
+ const variantFields = Object.values(x)[0]
167
+ const tag = schema.enumVariantTypes.findIndex(
168
+ (v) => v.name == variantName
169
+ )
170
+ if (tag != -1) {
171
+ throw new Error("invalid variant")
172
+ }
173
+
174
+ return new ConstrData(
175
+ tag,
176
+ schema.enumVariantTypes[tag].fieldTypes.map((f) =>
177
+ schemaToUplc(f.type, variantFields[f.name])
178
+ )
179
+ )
180
+ } else {
181
+ throw new Error("not yet implemented")
182
+ }
183
+ }
184
+
185
+ /**
186
+ * @param {TypeSchema} schema
187
+ * @param {UplcData} data
188
+ * @returns {any}
189
+ */
190
+ function uplcToSchema(schema, data) {
191
+ if ("primitiveType" in schema) {
192
+ switch (schema.primitiveType) {
193
+ case "Address":
194
+ return Address.fromUplcData(data)
195
+ case "Any":
196
+ // TODO: should this throw an error?
197
+ return null
198
+ case "Bool":
199
+ return ConstrData.expect(data).tag == 1
200
+ case "ByteArray":
201
+ return ByteArrayData.expect(data).bytes
202
+ case "Credential":
203
+ return Credential.fromUplcData(data)
204
+ case "Data":
205
+ return data
206
+ case "DCert":
207
+ throw new Error(
208
+ "can't convert UplcData back into DCert (significant loss of information)"
209
+ )
210
+ case "MintingPolicyHash":
211
+ return MintingPolicyHash.fromUplcData(data)
212
+ case "PubKeyHash":
213
+ return PubKeyHash.fromUplcData(data)
214
+ case "Real":
215
+ return (
216
+ Number(IntData.expect(data).value) /
217
+ Math.pow(10, REAL_PRECISION)
218
+ )
219
+ case "ScriptHash":
220
+ return ScriptHash.fromUplcData(data)
221
+ case "StakingCredential":
222
+ return StakingCredential.fromUplcData(data)
223
+ case "StakingHash":
224
+ return StakingHash.fromUplcData(data)
225
+ case "StakingValidatorHash":
226
+ return StakingValidatorHash.fromUplcData(data)
227
+ case "String":
228
+ return decodeUtf8(ByteArrayData.expect(data).bytes)
229
+ case "Time":
230
+ return new Date(Number(IntData.expect(data).value))
231
+ case "TimeRange":
232
+ return TimeRange.fromUplcData(data)
233
+ case "TxId":
234
+ return TxId.fromUplcData(data)
235
+ case "TxOutputId":
236
+ return TxOutputId.fromUplcData(data)
237
+ case "ValidatorHash":
238
+ return ValidatorHash.fromUplcData(data)
239
+ case "Value":
240
+ return Value.fromUplcData(data)
241
+ default:
242
+ throw new Error("not yet implemented")
243
+ }
244
+ } else if ("listItemType" in schema) {
245
+ return ListData.expect(data).items.map((x) =>
246
+ uplcToSchema(schema.listItemType, x)
247
+ )
248
+ } else if ("mapKeyType" in schema) {
249
+ return new Map(
250
+ MapData.expect(data).items.map(([k, v]) => [
251
+ uplcToSchema(schema.mapKeyType, k),
252
+ uplcToSchema(schema.mapValueType, v)
253
+ ])
254
+ )
255
+ } else if ("optionSomeType" in schema) {
256
+ const optionData = decodeOptionData(data)
257
+ return optionData
258
+ ? uplcToSchema(schema.optionSomeType, optionData)
259
+ : None
260
+ } else if ("structFieldTypes" in schema) {
261
+ // TODO: Cip-68 support
262
+ if (schema.structFieldTypes.length == 1) {
263
+ return {
264
+ [schema.structFieldTypes[0].name]: uplcToSchema(
265
+ schema.structFieldTypes[0].type,
266
+ data
267
+ )
268
+ }
269
+ } else {
270
+ return Object.fromEntries(
271
+ ListData.expect(data).items.map((item, i) => [
272
+ schema.structFieldTypes[i].name,
273
+ uplcToSchema(schema.structFieldTypes[i].type, item)
274
+ ])
275
+ )
276
+ }
277
+ } else if ("enumVariantTypes" in schema) {
278
+ const { tag, fields } = ConstrData.expect(data)
279
+
280
+ const variantSchema = schema.enumVariantTypes[tag]
281
+
282
+ return {
283
+ [variantSchema.name]: Object.fromEntries(
284
+ fields.map((f, i) => [
285
+ variantSchema.fieldTypes[i].name,
286
+ uplcToSchema(variantSchema.fieldTypes[i].type, f)
287
+ ])
288
+ )
289
+ }
290
+ } else {
291
+ throw new Error("not yet implemented")
292
+ }
293
+ }
package/.prettierignore DELETED
@@ -1,4 +0,0 @@
1
- **/node_modules
2
- *.d.ts
3
- *.d.ts.map
4
- **/*.md