@helios-lang/effect 0.1.0 → 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.
- package/dist/Ledger/Address.js +153 -0
- package/dist/Ledger/Address.js.map +1 -0
- package/dist/Ledger/Credential.js +17 -0
- package/dist/Ledger/Credential.js.map +1 -0
- package/dist/Ledger/PubKeyHash.js +21 -0
- package/dist/Ledger/PubKeyHash.js.map +1 -0
- package/dist/Ledger/ValidatorHash.js +21 -0
- package/dist/Ledger/ValidatorHash.js.map +1 -0
- package/dist/Ledger/index.js +5 -0
- package/dist/Ledger/index.js.map +1 -0
- package/dist/Uplc/Data.js +209 -21
- package/dist/Uplc/Data.js.map +1 -1
- package/dist/Uplc/index.js +0 -1
- package/dist/Uplc/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +13 -10
- package/src/Ledger/Address.ts +238 -0
- package/src/Ledger/Credential.ts +29 -0
- package/src/Ledger/PubKeyHash.ts +36 -0
- package/src/Ledger/ValidatorHash.ts +36 -0
- package/src/Ledger/index.ts +4 -0
- package/src/Uplc/Data.test.ts +321 -0
- package/src/Uplc/Data.ts +418 -47
- package/src/Uplc/index.ts +0 -1
- package/src/index.ts +1 -1
- package/src/Address.ts +0 -20
- package/src/Uplc/DataSchema.test.ts +0 -207
- package/src/Uplc/DataSchema.ts +0 -181
package/package.json
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helios-lang/effect",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"prettify": "prettier . --write",
|
|
11
|
-
"test": "pnpm run test:types && pnpm run lint && pnpm run test:suite",
|
|
12
|
-
"test:suite": "bun test .",
|
|
13
|
-
"test:types": "tsc -p ./tsconfig.json"
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./Uplc": "./dist/Uplc/index.js"
|
|
14
10
|
},
|
|
15
11
|
"keywords": [],
|
|
16
12
|
"author": "Christian Schmitz",
|
|
17
13
|
"license": "BSD-3-Clause",
|
|
18
|
-
"packageManager": "pnpm@10.20.0",
|
|
19
14
|
"prettier": {
|
|
20
15
|
"trailingComma": "none",
|
|
21
16
|
"tabWidth": 2,
|
|
@@ -32,5 +27,13 @@
|
|
|
32
27
|
},
|
|
33
28
|
"dependencies": {
|
|
34
29
|
"effect": "^3.19.12"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc -p ./tsconfig.build.json",
|
|
33
|
+
"lint": "eslint",
|
|
34
|
+
"prettify": "prettier . --write",
|
|
35
|
+
"test": "pnpm run test:types && pnpm run lint && pnpm run test:suite",
|
|
36
|
+
"test:suite": "bun test .",
|
|
37
|
+
"test:types": "tsc -p ./tsconfig.json"
|
|
35
38
|
}
|
|
36
|
-
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { Context, Effect, Option, ParseResult, Schema } from "effect"
|
|
2
|
+
import * as Bech32 from "../Bech32.js"
|
|
3
|
+
import * as Cbor from "../Cbor.js"
|
|
4
|
+
import * as Bytes from "../internal/Bytes.js"
|
|
5
|
+
import { Data } from "../Uplc/index.js"
|
|
6
|
+
import * as PubKeyHash from "./PubKeyHash.js"
|
|
7
|
+
import * as Credential from "./Credential.js"
|
|
8
|
+
import * as ValidatorHash from "./ValidatorHash.js"
|
|
9
|
+
|
|
10
|
+
export function isValid(addr: string): boolean {
|
|
11
|
+
if (addr.startsWith("addr1") || addr.startsWith("addr_test1")) {
|
|
12
|
+
return Bech32.isValid(addr) // TODO: full validation
|
|
13
|
+
}
|
|
14
|
+
// TODO: validate Byron format
|
|
15
|
+
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class IsMainnet extends Context.Tag("IS_MAINNET")<
|
|
20
|
+
IsMainnet,
|
|
21
|
+
boolean
|
|
22
|
+
>() {}
|
|
23
|
+
|
|
24
|
+
export const Address = Schema.String.pipe(
|
|
25
|
+
Schema.filter((addr: string) => {
|
|
26
|
+
return isValid(addr) || "Invalid Cardano Address"
|
|
27
|
+
}),
|
|
28
|
+
Schema.brand("Address")
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
export type Address = Schema.Schema.Type<typeof Address>
|
|
32
|
+
|
|
33
|
+
export const FromUplcData = Schema.transformOrFail(
|
|
34
|
+
Data.EnumVariant(0, {
|
|
35
|
+
spendingCredential: Credential.FromUplcData,
|
|
36
|
+
stakingCredential: Data.Option(Credential.FromUplcData)
|
|
37
|
+
}),
|
|
38
|
+
Address,
|
|
39
|
+
{
|
|
40
|
+
strict: true,
|
|
41
|
+
decode: (data) =>
|
|
42
|
+
Effect.gen(function* () {
|
|
43
|
+
const isMainnet = yield* IsMainnet
|
|
44
|
+
|
|
45
|
+
return make(
|
|
46
|
+
isMainnet,
|
|
47
|
+
data.spendingCredential,
|
|
48
|
+
data.stakingCredential._tag == "Some"
|
|
49
|
+
? data.stakingCredential.value
|
|
50
|
+
: undefined
|
|
51
|
+
)
|
|
52
|
+
}),
|
|
53
|
+
encode: (address) => {
|
|
54
|
+
const { spendingCredential, stakingCredential } = Effect.runSync(
|
|
55
|
+
decodeInternal(address)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return ParseResult.succeed({
|
|
59
|
+
spendingCredential,
|
|
60
|
+
stakingCredential: stakingCredential
|
|
61
|
+
? Option.some(stakingCredential)
|
|
62
|
+
: Option.none()
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
export function make(
|
|
69
|
+
isMainnet: boolean,
|
|
70
|
+
spendingCredential: Credential.Credential,
|
|
71
|
+
stakingCredential?: Credential.Credential
|
|
72
|
+
) {
|
|
73
|
+
const prefix = isMainnet ? "addr" : "addr_test"
|
|
74
|
+
const bytes: number[] = toShelleyBytes(
|
|
75
|
+
isMainnet,
|
|
76
|
+
spendingCredential,
|
|
77
|
+
stakingCredential
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
const s: string = Bech32.encode(prefix, bytes)
|
|
81
|
+
|
|
82
|
+
return s as Address
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// returns the byte representation of an Address
|
|
86
|
+
function toShelleyBytes(
|
|
87
|
+
isMainnet: boolean,
|
|
88
|
+
spendingCredential: Credential.Credential,
|
|
89
|
+
stakingCredential?: Credential.Credential
|
|
90
|
+
): number[] {
|
|
91
|
+
const spendingCredBytes = Bytes.toArray(spendingCredential.hash)
|
|
92
|
+
|
|
93
|
+
if (stakingCredential) {
|
|
94
|
+
const stakingCredBytes = Bytes.toArray(stakingCredential.hash)
|
|
95
|
+
|
|
96
|
+
if (spendingCredential._tag == "PubKey") {
|
|
97
|
+
if (stakingCredential._tag == "PubKey") {
|
|
98
|
+
return [isMainnet ? 0x01 : 0x00]
|
|
99
|
+
.concat(spendingCredBytes)
|
|
100
|
+
.concat(stakingCredBytes)
|
|
101
|
+
} else {
|
|
102
|
+
return [isMainnet ? 0x21 : 0x20]
|
|
103
|
+
.concat(spendingCredBytes)
|
|
104
|
+
.concat(stakingCredBytes)
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
if (stakingCredential._tag == "PubKey") {
|
|
108
|
+
return [isMainnet ? 0x11 : 0x10]
|
|
109
|
+
.concat(spendingCredBytes)
|
|
110
|
+
.concat(stakingCredBytes)
|
|
111
|
+
} else {
|
|
112
|
+
return [isMainnet ? 0x31 : 0x30]
|
|
113
|
+
.concat(spendingCredBytes)
|
|
114
|
+
.concat(stakingCredBytes)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} else if (spendingCredential._tag == "PubKey") {
|
|
118
|
+
return [isMainnet ? 0x61 : 0x60].concat(spendingCredBytes)
|
|
119
|
+
} else {
|
|
120
|
+
return [isMainnet ? 0x71 : 0x70].concat(spendingCredBytes)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const decodeInternal = (bytes: Bytes.BytesLike) =>
|
|
125
|
+
Effect.gen(function* () {
|
|
126
|
+
if (typeof bytes == "string" && bytes.startsWith("addr")) {
|
|
127
|
+
bytes = (yield* Bech32.decode(bytes)).bytes
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const innerBytes = (yield* Cbor.isBytes(bytes))
|
|
131
|
+
? (yield* Cbor.decodeBytes(bytes))
|
|
132
|
+
: Bytes.toArray(bytes)
|
|
133
|
+
|
|
134
|
+
const head = innerBytes[0]
|
|
135
|
+
|
|
136
|
+
const isMainnet = (head & 0b00001111) != 0
|
|
137
|
+
|
|
138
|
+
const type = head & 0b11110000
|
|
139
|
+
|
|
140
|
+
const firstPart = () => {
|
|
141
|
+
return innerBytes.slice(1, 29)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const secondPart = () => {
|
|
145
|
+
return innerBytes.slice(29, 57)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
switch (type) {
|
|
149
|
+
case 0x00:
|
|
150
|
+
return {
|
|
151
|
+
isMainnet,
|
|
152
|
+
spendingCredential: Credential.makePubKey(
|
|
153
|
+
yield* PubKeyHash.make(firstPart())
|
|
154
|
+
),
|
|
155
|
+
stakingCredential: Credential.makePubKey(
|
|
156
|
+
yield* PubKeyHash.make(secondPart())
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
case 0x10:
|
|
160
|
+
return {
|
|
161
|
+
isMainnet,
|
|
162
|
+
spendingCredential: Credential.makeValidator(
|
|
163
|
+
yield* ValidatorHash.make(firstPart())
|
|
164
|
+
),
|
|
165
|
+
stakingCredential: Credential.makePubKey(
|
|
166
|
+
yield* PubKeyHash.make(secondPart())
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
case 0x20:
|
|
170
|
+
return {
|
|
171
|
+
isMainnet,
|
|
172
|
+
spendingCredential: Credential.makePubKey(
|
|
173
|
+
yield* PubKeyHash.make(firstPart())
|
|
174
|
+
),
|
|
175
|
+
stakingCredential: Credential.makeValidator(
|
|
176
|
+
yield* ValidatorHash.make(secondPart())
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
case 0x30:
|
|
180
|
+
return {
|
|
181
|
+
isMainnet,
|
|
182
|
+
spendingCredential: Credential.makeValidator(
|
|
183
|
+
yield* ValidatorHash.make(firstPart())
|
|
184
|
+
),
|
|
185
|
+
stakingCredential: Credential.makeValidator(
|
|
186
|
+
yield* ValidatorHash.make(secondPart())
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
case 0x60:
|
|
190
|
+
return {
|
|
191
|
+
isMainnet,
|
|
192
|
+
spendingCredential: Credential.makePubKey(
|
|
193
|
+
yield* PubKeyHash.make(firstPart())
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
case 0x70:
|
|
197
|
+
return {
|
|
198
|
+
isMainnet,
|
|
199
|
+
spendingCredential: Credential.makeValidator(
|
|
200
|
+
yield* ValidatorHash.make(firstPart())
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
default:
|
|
204
|
+
return yield* Effect.fail(
|
|
205
|
+
new Error(`invalid Shelley Address header ${head}`)
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
export const decode = (bytes: Bytes.BytesLike) =>
|
|
211
|
+
Effect.gen(function* () {
|
|
212
|
+
const { isMainnet, spendingCredential, stakingCredential } =
|
|
213
|
+
yield* decodeInternal(bytes)
|
|
214
|
+
|
|
215
|
+
return make(isMainnet, spendingCredential, stakingCredential)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
export function encode(address: Address): number[] {
|
|
219
|
+
return Cbor.encodeBytes(bytes(address))
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function bytes(address: Address): number[] {
|
|
223
|
+
return Effect.runSync(Bech32.decode(address)).bytes
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function isMainnet(address: Address): boolean {
|
|
227
|
+
return !address.startsWith("addr_test")
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function spendingCredential(address: Address): Credential.Credential {
|
|
231
|
+
return Effect.runSync(decodeInternal(address)).spendingCredential
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function stakingCredential(
|
|
235
|
+
address: Address
|
|
236
|
+
): Credential.Credential | undefined {
|
|
237
|
+
return Effect.runSync(decodeInternal(address)).stakingCredential
|
|
238
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Schema } from "effect"
|
|
2
|
+
import { PubKeyHash } from "./PubKeyHash.js"
|
|
3
|
+
import { ValidatorHash } from "./ValidatorHash.js"
|
|
4
|
+
import { Data } from "../Uplc/index.js"
|
|
5
|
+
|
|
6
|
+
export const Credential = Schema.Union(
|
|
7
|
+
Schema.TaggedStruct("PubKey", { hash: PubKeyHash }),
|
|
8
|
+
Schema.TaggedStruct("Validator", { hash: ValidatorHash })
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
export type Credential = Schema.Schema.Type<typeof Credential>
|
|
12
|
+
|
|
13
|
+
export function makePubKey(pkh: PubKeyHash): Credential {
|
|
14
|
+
return { _tag: "PubKey", hash: pkh }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function makeValidator(vh: ValidatorHash): Credential {
|
|
18
|
+
return { _tag: "Validator", hash: vh }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const FromUplcData = Schema.transform(
|
|
22
|
+
Data.Enum({ PubKey: { hash: Data.Hex }, Validator: { hash: Data.Hex } }),
|
|
23
|
+
Credential,
|
|
24
|
+
{
|
|
25
|
+
strict: true,
|
|
26
|
+
decode: (cred) => cred,
|
|
27
|
+
encode: (cred) => cred
|
|
28
|
+
}
|
|
29
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Effect, Encoding, Schema } from "effect"
|
|
2
|
+
import * as Bytes from "../internal/Bytes.js"
|
|
3
|
+
import { decodeBytes, DecodeEffect, encodeBytes } from "../Cbor.js"
|
|
4
|
+
import { Data } from "../Uplc/index.js"
|
|
5
|
+
|
|
6
|
+
export function isValid(pkh: string): boolean {
|
|
7
|
+
return /^[0-9a-fA-F]+$/.test(pkh) && pkh.length == 56
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const PubKeyHash = Schema.String.pipe(
|
|
11
|
+
Schema.filter((pkh: string) => isValid(pkh) || "Invalid Cardano PubKeyHash"),
|
|
12
|
+
Schema.brand("PubKeyHash")
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
export type PubKeyHash = Schema.Schema.Type<typeof PubKeyHash>
|
|
16
|
+
|
|
17
|
+
export function make(bytes: Bytes.BytesLike) {
|
|
18
|
+
return Schema.decode(PubKeyHash)(Bytes.toHex(bytes))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const FromUplcData = Schema.transform(Data.ByteArray, PubKeyHash, {
|
|
22
|
+
strict: true,
|
|
23
|
+
decode: Encoding.encodeHex,
|
|
24
|
+
encode: (s) => Effect.runSync(Encoding.decodeHex(s))
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const decode = (bytes: Bytes.BytesLike): DecodeEffect<PubKeyHash> =>
|
|
28
|
+
decodeBytes(bytes).pipe(
|
|
29
|
+
Effect.map((bytes) => new Uint8Array(bytes)),
|
|
30
|
+
Effect.map(Encoding.encodeHex),
|
|
31
|
+
Effect.map(Schema.decodeSync(PubKeyHash))
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
export function encode(pkh: PubKeyHash): number[] {
|
|
35
|
+
return encodeBytes(pkh)
|
|
36
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Effect, Encoding, Schema } from "effect"
|
|
2
|
+
import * as Bytes from "../internal/Bytes.js"
|
|
3
|
+
import { decodeBytes, DecodeEffect, encodeBytes } from "../Cbor.js"
|
|
4
|
+
import { Data } from "../Uplc/index.js"
|
|
5
|
+
|
|
6
|
+
export function isValid(vh: string): boolean {
|
|
7
|
+
return /^[0-9a-fA-F]+$/.test(vh) && vh.length == 56
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const ValidatorHash = Schema.String.pipe(
|
|
11
|
+
Schema.filter((vh: string) => isValid(vh) || "Invalid Cardano ValidatorHash"),
|
|
12
|
+
Schema.brand("ValidatorHash")
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
export type ValidatorHash = Schema.Schema.Type<typeof ValidatorHash>
|
|
16
|
+
|
|
17
|
+
export function make(bytes: Bytes.BytesLike) {
|
|
18
|
+
return Schema.decode(ValidatorHash)(Bytes.toHex(bytes))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const FromUplcData = Schema.transform(Data.ByteArray, ValidatorHash, {
|
|
22
|
+
strict: true,
|
|
23
|
+
decode: Encoding.encodeHex,
|
|
24
|
+
encode: Bytes.toUint8Array
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const decode = (bytes: Bytes.BytesLike): DecodeEffect<ValidatorHash> =>
|
|
28
|
+
decodeBytes(bytes).pipe(
|
|
29
|
+
Effect.map((bytes) => new Uint8Array(bytes)),
|
|
30
|
+
Effect.map(Encoding.encodeHex),
|
|
31
|
+
Effect.map(Schema.decodeSync(ValidatorHash))
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
export function encode(vh: ValidatorHash): number[] {
|
|
35
|
+
return encodeBytes(vh)
|
|
36
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
|
+
import { Schema } from "effect"
|
|
3
|
+
import * as Data from "./Data.js"
|
|
4
|
+
|
|
5
|
+
describe("Uplc.DataSchema.BigInt", () => {
|
|
6
|
+
it("succeeds for {int: 0n}", () => {
|
|
7
|
+
expect(Schema.decodeSync(Data.BigInt)({ int: 0n })).toBe(0n)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it("fails for {int: '0'}", () => {
|
|
11
|
+
expect(() => Schema.decodeUnknownSync(Data.BigInt)({ int: "0" })).toThrow()
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
describe("Uplc.DataSchema.Int", () => {
|
|
16
|
+
it("succeeds for {int: 0n}", () => {
|
|
17
|
+
expect(Schema.decodeSync(Data.Int)({ int: 0n })).toBe(0)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("fails for {int: '0'}", () => {
|
|
21
|
+
expect(() => Schema.decodeUnknownSync(Data.Int)({ int: "0" })).toThrow()
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe("Uplc.DataSchema.String", () => {
|
|
26
|
+
it("succeeds for {bytes: ''}", () => {
|
|
27
|
+
expect(Schema.decodeSync(Data.String)(Data.makeByteArrayData(""))).toBe("")
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it("fails for {bytes: 'ff'}", () => {
|
|
31
|
+
expect(() =>
|
|
32
|
+
Schema.decodeSync(Data.String)(Data.makeByteArrayData("ff"))
|
|
33
|
+
).toThrow()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("succeeds for {bytes: '48656C6C6F20576F726C64'}", () => {
|
|
37
|
+
expect(
|
|
38
|
+
Schema.decodeSync(Data.String)(
|
|
39
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64")
|
|
40
|
+
)
|
|
41
|
+
).toBe("Hello World")
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe("Uplc.DataSchema.Array", () => {
|
|
46
|
+
it("succeeds for empty ListData", () => {
|
|
47
|
+
expect(Schema.decodeSync(Data.Array(Data.String))({ list: [] })).toEqual([])
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it("succeeds for ListData containg single 'Hello World' string", () => {
|
|
51
|
+
expect(
|
|
52
|
+
Schema.decodeSync(Data.Array(Data.String))({
|
|
53
|
+
list: [Data.makeByteArrayData("48656C6C6F20576F726C64")]
|
|
54
|
+
})
|
|
55
|
+
).toEqual(["Hello World"])
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it("fails if ListData items are heterogenous", () => {
|
|
59
|
+
expect(() =>
|
|
60
|
+
Schema.decodeSync(Data.Array(Data.String))({
|
|
61
|
+
list: [
|
|
62
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
63
|
+
Data.makeIntData(0)
|
|
64
|
+
]
|
|
65
|
+
})
|
|
66
|
+
).toThrow()
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe("Uplc.DataSchema.Struct", () => {
|
|
71
|
+
it("succeeds for empty ListData for empty Struct", () => {
|
|
72
|
+
expect(Schema.decodeSync(Data.Struct({}))({ list: [] })).toEqual({})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it("fails for empty ListData if one field is defined", () => {
|
|
76
|
+
expect(() =>
|
|
77
|
+
Schema.decodeSync(Data.Struct({ foo: Data.String }))({
|
|
78
|
+
list: []
|
|
79
|
+
})
|
|
80
|
+
).toThrow()
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it("succeeds for ListData with single entry if one field is defined", () => {
|
|
84
|
+
expect(
|
|
85
|
+
Schema.decodeSync(Data.Struct({ foo: Data.String }))({
|
|
86
|
+
list: [Data.makeByteArrayData("48656C6C6F20576F726C64")]
|
|
87
|
+
})
|
|
88
|
+
).toEqual({ foo: "Hello World" })
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it("fails for ListData with wrong entry in first place with one field is defined", () => {
|
|
92
|
+
expect(() =>
|
|
93
|
+
Schema.decodeSync(Data.Struct({ foo: Data.String }))({
|
|
94
|
+
list: [{ int: 0n }]
|
|
95
|
+
})
|
|
96
|
+
).toThrow()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it("succeeds for ListData with spurious entries at end with one field is defined", () => {
|
|
100
|
+
expect(
|
|
101
|
+
Schema.decodeSync(Data.Struct({ foo: Data.String }))({
|
|
102
|
+
list: [
|
|
103
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
104
|
+
Data.makeIntData(0)
|
|
105
|
+
]
|
|
106
|
+
})
|
|
107
|
+
).toEqual({ foo: "Hello World" })
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it("succeeds for ListData with two entries with two fields", () => {
|
|
111
|
+
expect(
|
|
112
|
+
Schema.decodeSync(Data.Struct({ foo: Data.String, bar: Data.Int }))({
|
|
113
|
+
list: [
|
|
114
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
115
|
+
Data.makeIntData(0n)
|
|
116
|
+
]
|
|
117
|
+
})
|
|
118
|
+
).toEqual({ foo: "Hello World", bar: 0 })
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it("fails for ListData with two entries in wrong order with two fields", () => {
|
|
122
|
+
expect(() =>
|
|
123
|
+
Schema.decodeSync(Data.Struct({ bar: Data.Int, foo: Data.String }))({
|
|
124
|
+
list: [
|
|
125
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
126
|
+
Data.makeIntData(0n)
|
|
127
|
+
]
|
|
128
|
+
})
|
|
129
|
+
).toThrow()
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
describe("Uplc.DataSchema.EnumVariant", () => {
|
|
134
|
+
it("succeeds for empty ConstrData for empty EnumVariant", () => {
|
|
135
|
+
expect(
|
|
136
|
+
Schema.decodeSync(Data.EnumVariant(0, {}))({
|
|
137
|
+
constructor: 0,
|
|
138
|
+
fields: []
|
|
139
|
+
})
|
|
140
|
+
).toEqual({})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it("fields for ConstrData with wrong tag", () => {
|
|
144
|
+
expect(() =>
|
|
145
|
+
Schema.decodeSync(Data.EnumVariant(0, {}))({
|
|
146
|
+
constructor: 1,
|
|
147
|
+
fields: []
|
|
148
|
+
})
|
|
149
|
+
).toThrow()
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it("fails for empty ConstrData if one field is defined", () => {
|
|
153
|
+
expect(() =>
|
|
154
|
+
Schema.decodeSync(Data.EnumVariant(0, { foo: Data.String }))({
|
|
155
|
+
constructor: 0,
|
|
156
|
+
fields: []
|
|
157
|
+
})
|
|
158
|
+
).toThrow()
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it("succeeds for ConstrData with single entry if one field is defined", () => {
|
|
162
|
+
expect(
|
|
163
|
+
Schema.decodeSync(Data.EnumVariant(0, { foo: Data.String }))({
|
|
164
|
+
constructor: 0,
|
|
165
|
+
fields: [Data.makeByteArrayData("48656C6C6F20576F726C64")]
|
|
166
|
+
})
|
|
167
|
+
).toEqual({ foo: "Hello World" })
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it("fails for ConstrData with wrong entry in first place with one field is defined", () => {
|
|
171
|
+
expect(() =>
|
|
172
|
+
Schema.decodeSync(Data.EnumVariant(0, { foo: Data.String }))({
|
|
173
|
+
constructor: 0,
|
|
174
|
+
fields: [{ int: 0n }]
|
|
175
|
+
})
|
|
176
|
+
).toThrow()
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it("succeeds for EnumVariant with spurious entries at end with one field is defined", () => {
|
|
180
|
+
expect(
|
|
181
|
+
Schema.decodeSync(Data.EnumVariant(0, { foo: Data.String }))({
|
|
182
|
+
constructor: 0,
|
|
183
|
+
fields: [
|
|
184
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
185
|
+
Data.makeIntData(0n)
|
|
186
|
+
]
|
|
187
|
+
})
|
|
188
|
+
).toEqual({ foo: "Hello World" })
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it("succeeds for EnumVariant with two entries with two fields", () => {
|
|
192
|
+
expect(
|
|
193
|
+
Schema.decodeSync(
|
|
194
|
+
Data.EnumVariant(0, {
|
|
195
|
+
foo: Data.String,
|
|
196
|
+
bar: Data.Int
|
|
197
|
+
})
|
|
198
|
+
)({
|
|
199
|
+
constructor: 0,
|
|
200
|
+
fields: [
|
|
201
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
202
|
+
Data.makeIntData(0n)
|
|
203
|
+
]
|
|
204
|
+
})
|
|
205
|
+
).toEqual({ foo: "Hello World", bar: 0 })
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it("fails for EnumVariant with two entries in wrong order with two fields", () => {
|
|
209
|
+
expect(() =>
|
|
210
|
+
Schema.decodeSync(
|
|
211
|
+
Data.EnumVariant(0, {
|
|
212
|
+
bar: Data.Int,
|
|
213
|
+
foo: Data.String
|
|
214
|
+
})
|
|
215
|
+
)({
|
|
216
|
+
constructor: 0,
|
|
217
|
+
fields: [
|
|
218
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
219
|
+
Data.makeIntData(0n)
|
|
220
|
+
]
|
|
221
|
+
})
|
|
222
|
+
).toThrow()
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
describe("Uplc.DataSchema.Enum", () => {
|
|
227
|
+
it("succeeds for empty ConstrData for empty EnumVariant", () => {
|
|
228
|
+
expect(
|
|
229
|
+
Schema.decodeSync(Data.Enum({ foo: {} }))({
|
|
230
|
+
constructor: 0,
|
|
231
|
+
fields: []
|
|
232
|
+
})
|
|
233
|
+
).toEqual({ _tag: "foo" })
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it("fields for ConstrData with wrong tag", () => {
|
|
237
|
+
expect(() =>
|
|
238
|
+
Schema.decodeSync(Data.Enum({ foo: {} }))({
|
|
239
|
+
constructor: 1,
|
|
240
|
+
fields: []
|
|
241
|
+
})
|
|
242
|
+
).toThrow()
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
it("fails for empty ConstrData if one field is defined", () => {
|
|
246
|
+
expect(() =>
|
|
247
|
+
Schema.decodeSync(Data.Enum({ foo: { bar: Data.String } }))({
|
|
248
|
+
constructor: 0,
|
|
249
|
+
fields: []
|
|
250
|
+
})
|
|
251
|
+
).toThrow()
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it("succeeds for ConstrData with single entry if one field is defined", () => {
|
|
255
|
+
expect(
|
|
256
|
+
Schema.decodeSync(Data.Enum({ foo: { bar: Data.String } }))({
|
|
257
|
+
constructor: 0,
|
|
258
|
+
fields: [Data.makeByteArrayData("48656C6C6F20576F726C64")]
|
|
259
|
+
})
|
|
260
|
+
).toEqual({ _tag: "foo", bar: "Hello World" })
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it("fails for ConstrData with wrong entry in first place with one field is defined", () => {
|
|
264
|
+
expect(() =>
|
|
265
|
+
Schema.decodeSync(Data.Enum({ foo: { bar: Data.String } }))({
|
|
266
|
+
constructor: 0,
|
|
267
|
+
fields: [{ int: 0n }]
|
|
268
|
+
})
|
|
269
|
+
).toThrow()
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it("succeeds for Enum with spurious entries at end with one field is defined", () => {
|
|
273
|
+
expect(
|
|
274
|
+
Schema.decodeSync(Data.Enum({ foo: { bar: Data.String } }))({
|
|
275
|
+
constructor: 0,
|
|
276
|
+
fields: [
|
|
277
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
278
|
+
Data.makeIntData(0n)
|
|
279
|
+
]
|
|
280
|
+
})
|
|
281
|
+
).toEqual({ _tag: "foo", bar: "Hello World" })
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it("succeeds for Enum with two entries with two fields", () => {
|
|
285
|
+
expect(
|
|
286
|
+
Schema.decodeSync(
|
|
287
|
+
Data.Enum({
|
|
288
|
+
foo: {
|
|
289
|
+
a: Data.String,
|
|
290
|
+
b: Data.Int
|
|
291
|
+
}
|
|
292
|
+
})
|
|
293
|
+
)({
|
|
294
|
+
constructor: 0,
|
|
295
|
+
fields: [
|
|
296
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
297
|
+
Data.makeIntData(0n)
|
|
298
|
+
]
|
|
299
|
+
})
|
|
300
|
+
).toEqual({ _tag: "foo", a: "Hello World", b: 0 })
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it("fails for Enum with two entries in wrong order with two fields", () => {
|
|
304
|
+
expect(() =>
|
|
305
|
+
Schema.decodeSync(
|
|
306
|
+
Data.Enum({
|
|
307
|
+
foo: {
|
|
308
|
+
a: Data.Int,
|
|
309
|
+
b: Data.String
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
)({
|
|
313
|
+
constructor: 0,
|
|
314
|
+
fields: [
|
|
315
|
+
Data.makeByteArrayData("48656C6C6F20576F726C64"),
|
|
316
|
+
Data.makeIntData(0n)
|
|
317
|
+
]
|
|
318
|
+
})
|
|
319
|
+
).toThrow()
|
|
320
|
+
})
|
|
321
|
+
})
|