Skip to content

Commit fefa6c7

Browse files
committed
feat: update modules
1 parent 6b4d5b6 commit fefa6c7

31 files changed

+739
-345
lines changed

packages/evolution/src/BaseAddress.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,15 @@ export class BaseAddress extends Schema.TaggedClass<BaseAddress>("BaseAddress")(
2323
networkId: NetworkId.NetworkId,
2424
paymentCredential: Credential.Credential,
2525
stakeCredential: Credential.Credential
26-
}) {}
26+
}) {
27+
toString(): string {
28+
return `BaseAddress { networkId: ${this.networkId}, paymentCredential: ${this.paymentCredential}, stakeCredential: ${this.stakeCredential} }`
29+
}
30+
31+
[Symbol.for("nodejs.util.inspect.custom")](): string {
32+
return this.toString()
33+
}
34+
}
2735

2836
export const FromBytes = Schema.transformOrFail(Bytes57.BytesSchema, BaseAddress, {
2937
strict: true,

packages/evolution/src/Certificate.ts

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import * as DRep from "./DRep.js"
99
import * as EpochNo from "./EpochNo.js"
1010
import * as Function from "./Function.js"
1111
import * as PoolKeyHash from "./PoolKeyHash.js"
12+
import * as PoolMetadata from "./PoolMetadata.js"
1213
import * as PoolParams from "./PoolParams.js"
14+
import * as Relay from "./Relay.js"
15+
import * as UnitInterval from "./UnitInterval.js"
1316

1417
/**
1518
* Error class for Certificate related operations.
@@ -215,7 +218,19 @@ export const CDDLSchema = Schema.Union(
215218
// 2: stake_delegation = (2, stake_credential, pool_keyhash)
216219
Schema.Tuple(Schema.Literal(2n), Credential.CDDLSchema, CBOR.ByteArray),
217220
// 3: pool_registration = (3, pool_params)
218-
Schema.Tuple(Schema.Literal(3n), PoolParams.CDDLSchema),
221+
Schema.Tuple(
222+
Schema.Literal(3n),
223+
// Flattened PoolParams.CDDLSchema
224+
CBOR.ByteArray, // operator (pool_keyhash as bytes)
225+
CBOR.ByteArray, // vrf_keyhash (as bytes)
226+
CBOR.Integer, // pledge (coin)
227+
CBOR.Integer, // cost (coin)
228+
UnitInterval.CDDLSchema, // margin
229+
CBOR.ByteArray, // reward_account (bytes)
230+
Schema.Array(CBOR.ByteArray), // pool_owners (array of addr_keyhash bytes)
231+
Schema.Array(Schema.encodedSchema(Relay.FromCDDL)), // relays
232+
Schema.NullOr(Schema.encodedSchema(PoolMetadata.FromCDDL)) // pool_metadata
233+
),
219234
// 4: pool_retirement = (4, pool_keyhash, epoch_no)
220235
Schema.Tuple(Schema.Literal(4n), CBOR.ByteArray, CBOR.Integer),
221236
// 7: reg_cert = (7, stake_credential , coin)
@@ -273,7 +288,8 @@ export const FromCDDL = Schema.transformOrFail(CDDLSchema, Schema.typeSchema(Cer
273288
}
274289
case "PoolRegistration": {
275290
const poolParamsCDDL = yield* ParseResult.encodeEither(PoolParams.FromCDDL)(toA.poolParams)
276-
return [3n, poolParamsCDDL] as const
291+
// Spread encoded PoolParams fields directly into the certificate tuple (flattening)
292+
return [3n, ...poolParamsCDDL] as const
277293
}
278294
case "PoolRetirement": {
279295
const poolKeyHashBytes = yield* ParseResult.encodeEither(PoolKeyHash.FromBytes)(toA.poolKeyHash)
@@ -370,9 +386,41 @@ export const FromCDDL = Schema.transformOrFail(CDDLSchema, Schema.typeSchema(Cer
370386
return new StakeDelegation({ stakeCredential, poolKeyHash }, { disableValidation: true })
371387
}
372388
case 3n: {
373-
// pool_registration = (3, pool_params)
374-
const [, poolParamsCDDL] = fromA
375-
const poolParams = yield* ParseResult.decodeEither(PoolParams.FromCDDL)(poolParamsCDDL)
389+
// pool_registration = (3, ...pool_params fields flattened)
390+
const [
391+
,
392+
operatorBytes,
393+
vrfKeyhashBytes,
394+
pledge,
395+
cost,
396+
marginEncoded,
397+
rewardAccountBytes,
398+
poolOwnersBytes,
399+
relaysEncoded,
400+
poolMetadataEncoded
401+
] = fromA as unknown as readonly [
402+
3n,
403+
Uint8Array,
404+
Uint8Array,
405+
bigint,
406+
bigint,
407+
unknown,
408+
Uint8Array,
409+
ReadonlyArray<Uint8Array>,
410+
ReadonlyArray<unknown>,
411+
unknown | null
412+
]
413+
const poolParams = yield* ParseResult.decodeEither(PoolParams.FromCDDL)([
414+
operatorBytes,
415+
vrfKeyhashBytes,
416+
pledge,
417+
cost,
418+
marginEncoded as any,
419+
rewardAccountBytes,
420+
poolOwnersBytes as any,
421+
relaysEncoded as any,
422+
poolMetadataEncoded as any
423+
] as any)
376424
return new PoolRegistration({ poolParams }, { disableValidation: true })
377425
}
378426
case 4n: {

packages/evolution/src/DatumOption.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,15 @@ export class DatumOptionError extends Data.TaggedError("DatumOptionError")<{
2626
*/
2727
export class DatumHash extends Schema.TaggedClass<DatumHash>()("DatumHash", {
2828
hash: Bytes32.BytesSchema
29-
}) {}
29+
}) {
30+
toString(): string {
31+
return `DatumHash { hash: ${this.hash} }`
32+
}
33+
34+
[Symbol.for("nodejs.util.inspect.custom")](): string {
35+
return this.toString()
36+
}
37+
}
3038

3139
export const DatumHashFromBytes = Schema.transform(Bytes32.BytesSchema, DatumHash, {
3240
strict: true,
@@ -45,7 +53,15 @@ export const DatumHashFromBytes = Schema.transform(Bytes32.BytesSchema, DatumHas
4553
*/
4654
export class InlineDatum extends Schema.TaggedClass<InlineDatum>()("InlineDatum", {
4755
data: PlutusData.DataSchema
48-
}) {}
56+
}) {
57+
toString(): string {
58+
return `InlineDatum { data: ${this.data} }`
59+
}
60+
61+
[Symbol.for("nodejs.util.inspect.custom")](): string {
62+
return this.toString()
63+
}
64+
}
4965

5066
/**
5167
* Schema for DatumOption representing optional datum information in transaction outputs.
@@ -136,19 +152,19 @@ export const arbitrary = FastCheck.oneof(datumHashArbitrary, inlineDatumArbitrar
136152

137153
/**
138154
* CDDL schema for DatumOption.
139-
* datum_option = [0, Bytes32// 1, data]
155+
* datum_option = [0, Bytes32] / [1, #6.24(bytes)]
140156
*
141157
* Where:
142158
* - [0, Bytes32] represents a datum hash (tag 0 with 32-byte hash)
143-
* - [1, data] represents inline data (tag 1 with CBOR-encoded plutus data)
159+
* - [1, #6.24(bytes)] represents inline data (tag 1 with CBOR tag 24 containing plutus data as bytes)
144160
*
145161
* @since 2.0.0
146162
* @category schemas
147163
*/
148164
export const DatumOptionCDDLSchema = Schema.transformOrFail(
149165
Schema.Union(
150166
Schema.Tuple(Schema.Literal(0n), CBOR.ByteArray), // [0, Bytes32]
151-
Schema.Tuple(Schema.Literal(1n), CBOR.CBORSchema) // [1, data] - data as CBOR bytes
167+
Schema.Tuple(Schema.Literal(1n), CBOR.tag(24, Schema.Uint8ArrayFromSelf)) // [1, tag(24, bytes)] - PlutusData as bytes in tag 24
152168
),
153169
Schema.typeSchema(DatumOptionSchema),
154170
{
@@ -158,7 +174,7 @@ export const DatumOptionCDDLSchema = Schema.transformOrFail(
158174
const result =
159175
toA._tag === "DatumHash"
160176
? ([0n, toA.hash] as const) // Encode as [0, Bytes32]
161-
: ([1n, PlutusData.plutusDataToCBORValue(toA.data)] as const) // Encode as [1, data]
177+
: ([1n, { _tag: "Tag" as const, tag: 24 as const, value: PlutusData.toCBORBytes(toA.data) }] as const) // Encode as [1, tag(24, bytes)]
162178
return yield* E.right(result)
163179
}),
164180
decode: ([tag, value], _, ast) =>
@@ -167,11 +183,21 @@ export const DatumOptionCDDLSchema = Schema.transformOrFail(
167183
// Decode as DatumHash
168184
return yield* E.right(new DatumHash({ hash: value }, { disableValidation: true }))
169185
} else if (tag === 1n) {
170-
// Decode as InlineDatum
186+
// Decode as InlineDatum - value is now a CBOR tag 24 wrapper containing bytes
187+
const taggedValue = value as { _tag: "Tag"; tag: number; value: Uint8Array }
188+
if (taggedValue._tag !== "Tag" || taggedValue.tag !== 24) {
189+
return yield* E.left(
190+
new ParseResult.Type(
191+
ast,
192+
[tag, value],
193+
`Invalid InlineDatum format: expected tag 24, got ${taggedValue._tag} with tag ${taggedValue.tag}`
194+
)
195+
)
196+
}
171197
return yield* E.right(
172198
new InlineDatum(
173199
{
174-
data: PlutusData.cborValueToPlutusData(value)
200+
data: PlutusData.fromCBORBytes(taggedValue.value)
175201
},
176202
{ disableValidation: true }
177203
)

packages/evolution/src/EnterpriseAddress.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,15 @@ export class EnterpriseAddressError extends Data.TaggedError("EnterpriseAddressE
2222
export class EnterpriseAddress extends Schema.TaggedClass<EnterpriseAddress>("EnterpriseAddress")("EnterpriseAddress", {
2323
networkId: NetworkId.NetworkId,
2424
paymentCredential: Credential.Credential
25-
}) {}
25+
}) {
26+
toString(): string {
27+
return `EnterpriseAddress { networkId: ${this.networkId}, paymentCredential: ${this.paymentCredential} }`
28+
}
29+
30+
[Symbol.for("nodejs.util.inspect.custom")](): string {
31+
return this.toString()
32+
}
33+
}
2634

2735
export const FromBytes = Schema.transformOrFail(Bytes29.BytesSchema, EnterpriseAddress, {
2836
strict: true,

packages/evolution/src/GovernanceAction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export const GovActionIdFromCDDL = Schema.transformOrFail(GovActionIdCDDL, GovAc
6969
const [transactionIdBytes, govActionIndexNumber] = fromA
7070
// Convert CBOR types to domain types
7171
const transactionId = yield* ParseResult.decode(TransactionHash.FromBytes)(transactionIdBytes)
72-
const govActionIndex = yield* ParseResult.decode(TransactionIndex.TransactionIndex)(Number(govActionIndexNumber))
72+
const govActionIndex = yield* ParseResult.decode(TransactionIndex.TransactionIndex)(govActionIndexNumber)
7373
return new GovActionId({ transactionId, govActionIndex })
7474
})
7575
})

packages/evolution/src/KeyHash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class KeyHash extends Schema.TaggedClass<KeyHash>()("KeyHash", {
3838
}
3939

4040
toString(): string {
41-
return toHex(this)
41+
return `KeyHash({ hash: ${this.hash} })`
4242
}
4343
}
4444

packages/evolution/src/Mint.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -325,16 +325,38 @@ export const FromCBORHex = (options: CBOR.CodecOptions = CBOR.CML_DEFAULT_OPTION
325325
* @since 2.0.0
326326
* @category arbitrary
327327
*/
328-
export const arbitrary = FastCheck.array(
329-
FastCheck.tuple(
330-
PolicyId.arbitrary,
331-
FastCheck.array(FastCheck.tuple(AssetName.arbitrary, NonZeroInt64.arbitrary.map(NonZeroInt64.make)), {
332-
minLength: 1,
333-
maxLength: 5
334-
})
335-
),
336-
{ minLength: 0, maxLength: 5 }
337-
).map((entries) => fromEntries(entries))
328+
export const arbitrary: FastCheck.Arbitrary<Mint> = FastCheck.oneof(
329+
// Sometimes generate an empty mint map
330+
FastCheck.constant(empty()),
331+
// Non-empty unique policies with unique assets per policy
332+
FastCheck.uniqueArray(PolicyId.arbitrary, {
333+
minLength: 1,
334+
maxLength: 5,
335+
selector: (p) => Bytes.toHexUnsafe(p.hash)
336+
}).chain((policies) => {
337+
const assetsForPolicy = () =>
338+
FastCheck.uniqueArray(AssetName.arbitrary, {
339+
minLength: 1,
340+
maxLength: 5,
341+
selector: (a) => Bytes.toHexUnsafe(a.bytes)
342+
}).chain((names) =>
343+
FastCheck.array(NonZeroInt64.arbitrary.map(NonZeroInt64.make), {
344+
minLength: names.length,
345+
maxLength: names.length
346+
}).map((amounts) => names.map((n, i) => [n, amounts[i]] as const))
347+
)
348+
349+
return FastCheck.array(assetsForPolicy(), { minLength: policies.length, maxLength: policies.length }).map(
350+
(assetsEntries) =>
351+
fromEntries(
352+
policies.map((policy, idx) => [
353+
policy,
354+
assetsEntries[idx] as Array<[AssetName.AssetName, NonZeroInt64.NonZeroInt64]>
355+
])
356+
)
357+
)
358+
})
359+
)
338360

339361
// ============================================================================
340362
// Root Functions

packages/evolution/src/MultiAsset.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,32 @@ export const is = (value: unknown): value is MultiAsset => Schema.is(MultiAsset)
230230
* @since 2.0.0
231231
* @category arbitrary
232232
*/
233-
export const arbitrary = FastCheck.array(
234-
FastCheck.tuple(
235-
PolicyId.arbitrary,
236-
FastCheck.array(FastCheck.tuple(AssetName.arbitrary, PositiveCoin.arbitrary), { minLength: 1, maxLength: 5 }).map(
237-
(tokens) => new Map(tokens)
233+
export const arbitrary: FastCheck.Arbitrary<MultiAsset> = FastCheck.uniqueArray(PolicyId.arbitrary, {
234+
minLength: 1,
235+
maxLength: 5,
236+
selector: (p) => Bytes.toHexUnsafe(p.hash)
237+
}).chain((policies) => {
238+
// For each unique policy, generate a unique set of asset names with aligned positive amounts
239+
const assetsForPolicy = () =>
240+
FastCheck.uniqueArray(AssetName.arbitrary, {
241+
minLength: 1,
242+
maxLength: 5,
243+
selector: (a) => Bytes.toHexUnsafe(a.bytes)
244+
}).chain((names) =>
245+
// Generate exactly names.length amounts to pair with the unique names
246+
FastCheck.array(PositiveCoin.arbitrary, { minLength: names.length, maxLength: names.length }).map((amounts) => {
247+
const entries = names.map((n, i) => [n, amounts[i]] as const)
248+
return new Map(entries)
249+
})
238250
)
239-
),
240-
{ minLength: 1, maxLength: 5 }
241-
).map((entries) => make(new Map(entries)))
251+
252+
return FastCheck.array(assetsForPolicy(), { minLength: policies.length, maxLength: policies.length }).map(
253+
(assetMaps) => {
254+
const entries = policies.map((policy, idx) => [policy, assetMaps[idx]] as const)
255+
return make(new Map(entries))
256+
}
257+
)
258+
})
242259

243260
/**
244261
* CDDL schema for MultiAsset.

packages/evolution/src/NativeScripts.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Data, Either as E, ParseResult, Schema } from "effect"
1+
import { Data, Either as E, FastCheck, ParseResult, Schema } from "effect"
22
import type { ParseIssue } from "effect/ParseResult"
33

44
import * as Bytes from "./Bytes.js"
@@ -307,6 +307,60 @@ export const internalDecodeCDDL = (cborTuple: NativeCDDL): E.Either<Native, Pars
307307
}
308308
})
309309

310+
/**
311+
* FastCheck arbitrary for Native scripts.
312+
* Generates valid native scripts with bounded depth and sizes.
313+
*
314+
* Depth limit prevents exponential blow-up. At depth 0, only base cases are generated.
315+
*/
316+
const nativeArbitrary = (depth: number): FastCheck.Arbitrary<Native> => {
317+
const baseSig = FastCheck.record({
318+
type: FastCheck.constant("sig" as const),
319+
// 28-byte keyhash (56 hex chars)
320+
keyHash: FastCheck.hexaString({ minLength: 56, maxLength: 56 })
321+
})
322+
323+
const baseBefore = FastCheck.record({
324+
type: FastCheck.constant("before" as const),
325+
slot: FastCheck.integer({ min: 0, max: 10_000_000 })
326+
})
327+
328+
const baseAfter = FastCheck.record({
329+
type: FastCheck.constant("after" as const),
330+
slot: FastCheck.integer({ min: 0, max: 10_000_000 })
331+
})
332+
333+
if (depth <= 0) {
334+
return FastCheck.oneof(baseSig, baseBefore, baseAfter)
335+
}
336+
337+
const sub = nativeArbitrary(depth - 1)
338+
const scriptsArray = FastCheck.array(sub, { minLength: 0, maxLength: 3 })
339+
340+
const all = scriptsArray.map((scripts) => ({ type: "all" as const, scripts }))
341+
const any = scriptsArray.map((scripts) => ({ type: "any" as const, scripts }))
342+
343+
const atLeast = FastCheck.array(sub, { minLength: 0, maxLength: 4 }).chain((scripts) =>
344+
FastCheck.integer({ min: 0, max: scripts.length }).map((required) => ({
345+
type: "atLeast" as const,
346+
required,
347+
scripts
348+
}))
349+
)
350+
351+
// Weight base cases a bit higher for performance and balance
352+
return FastCheck.oneof(
353+
{ arbitrary: baseSig, weight: 3 },
354+
{ arbitrary: baseBefore, weight: 2 },
355+
{ arbitrary: baseAfter, weight: 2 },
356+
{ arbitrary: all, weight: 1 },
357+
{ arbitrary: any, weight: 1 },
358+
{ arbitrary: atLeast, weight: 1 }
359+
)
360+
}
361+
362+
export const arbitrary: FastCheck.Arbitrary<Native> = nativeArbitrary(2)
363+
310364
/**
311365
* CBOR bytes transformation schema for Native.
312366
* Transforms between CBOR bytes and Native using CBOR encoding.

packages/evolution/src/Natural.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class NaturalError extends Data.TaggedError("NaturalError")<{
1818
* @since 2.0.0
1919
* @category schemas
2020
*/
21-
export const Natural = Schema.Positive.pipe(Schema.brand("Natural")).annotations({
21+
export const Natural = Schema.Positive.annotations({
2222
identifier: "Natural",
2323
title: "Natural Number",
2424
description: "A positive integer greater than 0"

0 commit comments

Comments
 (0)