@@ -3,7 +3,7 @@ title: PlutusData
33description : On-chain data structures for Cardano smart contracts
44---
55
6- import { Card , Cards } from ' fumadocs-ui/components/card'
6+ import { Card , Cards } from " fumadocs-ui/components/card"
77
88# PlutusData
99
@@ -15,13 +15,13 @@ The Evolution SDK's Data module gives you type-safe PlutusData creation without
1515
1616PlutusData consists of five primitive types:
1717
18- | Type | TypeScript | Use For |
19- | ------| -----------| ---------|
20- | ** Integer** | ` bigint ` | Amounts, indices, timestamps, quantities |
21- | ** ByteArray** | ` Uint8Array ` | Hashes, addresses, policy IDs, asset names |
22- | ** Constructor** | ` { index: bigint, fields: Data[] } ` | Variants, tagged unions, structured data |
23- | ** Map** | ` Map<Data, Data> ` | Metadata, key-value stores |
24- | ** List** | ` ReadonlyArray<Data> ` | Arrays of values |
18+ | Type | TypeScript | Use For |
19+ | --------------- | ----------------------------------- | ------------------------------------------ |
20+ | ** Integer** | ` bigint ` | Amounts, indices, timestamps, quantities |
21+ | ** ByteArray** | ` Uint8Array ` | Hashes, addresses, policy IDs, asset names |
22+ | ** Constructor** | ` { index: bigint, fields: Data[] } ` | Variants, tagged unions, structured data |
23+ | ** Map** | ` Map<Data, Data> ` | Metadata, key-value stores |
24+ | ** List** | ` ReadonlyArray<Data> ` | Arrays of values |
2525
2626## Quick Start
2727
@@ -61,7 +61,7 @@ import { Bytes, Data, Text } from "@evolution-sdk/evolution"
6161const fee: Data .Data = 170000n
6262const deposit: Data .Data = 2000000n
6363
64- // Token quantities
64+ // Token quantities
6565const nftQuantity: Data .Data = 1n
6666const ftQuantity: Data .Data = 1000000n
6767
@@ -80,14 +80,10 @@ Raw bytes for hashes, addresses, and binary data:
8080import { Bytes , Data , Text } from " @evolution-sdk/evolution"
8181
8282// Transaction hash (32 bytes)
83- const txHash = Bytes .fromHex (
84- " a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
85- )
83+ const txHash = Bytes .fromHex (" a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2" )
8684
8785// Policy ID (28 bytes)
88- const policyId = Bytes .fromHex (
89- " 1234567890abcdef1234567890abcdef1234567890abcdef12345678"
90- )
86+ const policyId = Bytes .fromHex (" 1234567890abcdef1234567890abcdef1234567890abcdef12345678" )
9187
9288// Asset name (readable string)
9389const assetName = Text .toBytes (" MyToken" )
@@ -113,13 +109,9 @@ const claimAction = Data.constr(0n, [])
113109const cancelAction = Data .constr (1n , [])
114110
115111// Variant with single field
116- const verificationKeyCred = Data .constr (0n , [
117- Bytes .fromHex (" abc123def456abc123def456abc123def456abc123def456abc123de" )
118- ])
112+ const verificationKeyCred = Data .constr (0n , [Bytes .fromHex (" abc123def456abc123def456abc123def456abc123def456abc123de" )])
119113
120- const scriptCred = Data .constr (1n , [
121- Bytes .fromHex (" def456abc123def456abc123def456abc123def456abc123def456ab" )
122- ])
114+ const scriptCred = Data .constr (1n , [Bytes .fromHex (" def456abc123def456abc123def456abc123def456abc123def456ab" )])
123115
124116// Multiple fields
125117const outputRef = Data .constr (0n , [
@@ -149,10 +141,13 @@ const tokenMetadata = Data.map([
149141 [Text .toBytes (" name" ), Text .toBytes (" MyToken" )],
150142 [Text .toBytes (" ticker" ), Text .toBytes (" MTK" )],
151143 [Text .toBytes (" decimals" ), 6n ],
152- [Text .toBytes (" properties" ), Data .map ([
153- [Text .toBytes (" mintable" ), 1n ], // boolean as 0/1
154- [Text .toBytes (" burnable" ), 1n ]
155- ])]
144+ [
145+ Text .toBytes (" properties" ),
146+ Data .map ([
147+ [Text .toBytes (" mintable" ), 1n ], // boolean as 0/1
148+ [Text .toBytes (" burnable" ), 1n ]
149+ ])
150+ ]
156151])
157152```
158153
@@ -201,7 +196,7 @@ const datum = Data.constr(0n, [
201196const cborHex = Data .toCBORHex (datum )
202197// "d8799fa2646265..."
203198
204- // Encode to bytes
199+ // Encode to bytes
205200const cborBytes = Data .toCBORBytes (datum )
206201// Uint8Array [216, 121, 159, ...]
207202
@@ -260,10 +255,13 @@ const metadata = Data.map([
260255 [Text .toBytes (" name" ), Text .toBytes (" SpaceAce #4242" )],
261256 [Text .toBytes (" image" ), Text .toBytes (" ipfs://QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco" )],
262257 [Text .toBytes (" rarity" ), Text .toBytes (" legendary" )],
263- [Text .toBytes (" attributes" ), Data .map ([
264- [Text .toBytes (" class" ), Text .toBytes (" explorer" )],
265- [Text .toBytes (" power" ), 9000n ]
266- ])]
258+ [
259+ Text .toBytes (" attributes" ),
260+ Data .map ([
261+ [Text .toBytes (" class" ), Text .toBytes (" explorer" )],
262+ [Text .toBytes (" power" ), 9000n ]
263+ ])
264+ ]
267265])
268266
269267const cip68Datum = Data .constr (0n , [
@@ -315,6 +313,207 @@ Use the Data module directly when:
315313
316314For production smart contract integration, use [ TSchema] ( /docs/encoding/tschema ) for type-safe schema definitions with automatic validation.
317315
316+ ## Data.withSchema()
317+
318+ ` Data.withSchema() ` is the bridge between raw PlutusData and TSchema. It takes a TSchema definition and returns a codec with six methods for converting between your TypeScript types and CBOR:
319+
320+ ``` typescript twoslash
321+ import { Bytes , Data , TSchema } from " @evolution-sdk/evolution"
322+
323+ const EscrowSchema = TSchema .Struct ({
324+ beneficiary: TSchema .ByteArray ,
325+ deadline: TSchema .Integer ,
326+ amount: TSchema .Integer
327+ })
328+
329+ // Create codec from schema
330+ const EscrowCodec = Data .withSchema (EscrowSchema )
331+
332+ // Available methods:
333+ // EscrowCodec.toData(value) → PlutusData
334+ // EscrowCodec.fromData(data) → value
335+ // EscrowCodec.toCBORHex(value) → string
336+ // EscrowCodec.toCBORBytes(value) → Uint8Array
337+ // EscrowCodec.fromCBORHex(hex) → value
338+ // EscrowCodec.fromCBORBytes(bytes) → value
339+
340+ const datum = {
341+ beneficiary: Bytes .fromHex (" abc123def456abc123def456abc123def456abc123def456abc123de" ),
342+ deadline: 1735689600000n ,
343+ amount: 10000000n
344+ }
345+
346+ // Encode to CBOR hex (for use in transactions)
347+ const cborHex = EscrowCodec .toCBORHex (datum )
348+
349+ // Decode back from CBOR hex
350+ const decoded = EscrowCodec .fromCBORHex (cborHex )
351+
352+ // Convert to raw PlutusData
353+ const plutusData = EscrowCodec .toData (datum )
354+ ```
355+
356+ Use ` Data.withSchema() ` any time you have a TSchema definition and need to encode/decode values for on-chain use. For raw PlutusData without a schema, use ` Data.toCBORHex() ` directly.
357+
358+ ## Hashing PlutusData
359+
360+ Use ` Data.hashData() ` to compute the blake2b-256 hash of any PlutusData value over its CBOR encoding. This is used when you need to reference a datum by hash in a transaction output:
361+
362+ ``` typescript twoslash
363+ import { Bytes , Data , TSchema } from " @evolution-sdk/evolution"
364+
365+ const EscrowSchema = TSchema .Struct ({
366+ beneficiary: TSchema .ByteArray ,
367+ deadline: TSchema .Integer ,
368+ amount: TSchema .Integer
369+ })
370+
371+ const EscrowCodec = Data .withSchema (EscrowSchema )
372+
373+ const datum = {
374+ beneficiary: Bytes .fromHex (" abc123def456abc123def456abc123def456abc123def456abc123de" ),
375+ deadline: 1735689600000n ,
376+ amount: 10000000n
377+ }
378+
379+ // Convert to raw PlutusData first, then hash
380+ const plutusData = EscrowCodec .toData (datum )
381+ const datumHash = Data .hashData (plutusData )
382+
383+ console .log (datumHash ) // DatumHash instance (blake2b-256)
384+ ```
385+
386+ ## DataEncoded
387+
388+ ` DataEncoded ` is a TypeScript type representing PlutusData in its JSON-serializable form, based on the Conway CDDL specification. It is used internally for JSON encoding and is useful when you need to inspect or transmit PlutusData as plain JSON:
389+
390+ ``` typescript twoslash
391+ import { Data } from " @evolution-sdk/evolution"
392+
393+ // DataEncoded represents PlutusData in JSON-safe form:
394+ //
395+ // Constructor: { index: string, fields: DataEncoded[] }
396+ // Map: ReadonlyArray<readonly [DataEncoded, DataEncoded]>
397+ // List: ReadonlyArray<DataEncoded>
398+ // Integer: string (e.g. "42")
399+ // ByteArray: string (hex, e.g. "a1b2c3")
400+
401+ type MyDatumEncoded = Data .DataEncoded
402+
403+ // Example: a Constructor with one integer field
404+ const encoded: Data .DataEncoded = {
405+ index: " 0" ,
406+ fields: [" 5000000" ]
407+ }
408+ ```
409+
410+ You will rarely need to use ` DataEncoded ` directly — prefer ` Data.withSchema() ` with TSchema for type-safe encoding. ` DataEncoded ` is most useful when debugging raw PlutusData or building low-level serialization tools.
411+
412+ ## DataError
413+
414+ ` DataError ` is the tagged error class thrown by Data operations when encoding or decoding fails. It carries an optional ` message ` and ` cause ` for debugging:
415+
416+ ``` typescript twoslash
417+ import { Data , TSchema } from " @evolution-sdk/evolution"
418+
419+ const Schema = TSchema .Struct ({
420+ amount: TSchema .Integer
421+ })
422+
423+ const Codec = Data .withSchema (Schema )
424+
425+ try {
426+ // This will throw DataError if the CBOR is invalid or doesn't match the schema
427+ const result = Codec .fromCBORHex (" invalid_cbor_hex" )
428+ } catch (error ) {
429+ if (error instanceof Data .DataError ) {
430+ console .error (" Data decoding failed:" , error .message )
431+ console .error (" Caused by:" , error .cause )
432+ }
433+ }
434+ ```
435+
436+ ` DataError ` extends Effect's ` TaggedError ` , so it integrates cleanly with Effect-based error handling pipelines if your project uses Effect.
437+
438+ ## Constr Class vs Data.constr() Helper
439+
440+ The ` Data ` module provides two ways to create Constructor PlutusData — the ` Constr ` class and the ` Data.constr() ` convenience function. They produce the same result but serve different purposes:
441+
442+ ** ` Constr ` class** — the underlying schema class with typed ` index ` and ` fields ` properties. Use it when you need to inspect, pattern match, or type-check a constructor value:
443+
444+ ``` typescript twoslash
445+ import { Data } from " @evolution-sdk/evolution"
446+
447+ // Constr is a class with typed properties
448+ const constr = new Data .Constr ({ index: 0n , fields: [] })
449+
450+ console .log (constr .index ) // 0n
451+ console .log (constr .fields ) // []
452+
453+ // Useful for type checking
454+ if (constr instanceof Data .Constr ) {
455+ console .log (" It's a constructor with index:" , constr .index )
456+ }
457+ ```
458+
459+ ** ` Data.constr() ` helper** — a convenience function that calls ` Constr.make() ` internally. Use it when constructing PlutusData inline for brevity:
460+
461+ ``` typescript twoslash
462+ import { Bytes , Data } from " @evolution-sdk/evolution"
463+
464+ // Claim action (index 0, no fields)
465+ const claim = Data .constr (0n , [])
466+
467+ // Script credential (index 1, one field)
468+ const scriptCred = Data .constr (1n , [
469+ Data .bytearray (Bytes .fromHex (" abc123def456abc123def456abc123def456abc123def456abc123de" ))
470+ ])
471+
472+ // Equivalent to using the class directly:
473+ // new Data.Constr({ index: 0n, fields: [] })
474+ ```
475+
476+ ** When to use which:**
477+
478+ | | ` Constr ` class | ` Data.constr() ` |
479+ | ---------------------------- | -------------- | ---------------------- |
480+ | Constructing values | ✅ | ✅ Preferred (shorter) |
481+ | Type checking (` instanceof ` ) | ✅ | ❌ |
482+ | Pattern matching on fields | ✅ | ❌ |
483+ | Use in TSchema definitions | ✅ | ❌ |
484+ | Inline data building | ⚠️ Verbose | ✅ |
485+
486+ ** Rule of thumb** : Use ` Data.constr() ` when building data, use the ` Constr ` class when reading or inspecting it.
487+
488+ ## Helper API Reference
489+
490+ A quick reference of all ` Data ` module helpers:
491+
492+ | Function | Signature | Description |
493+ | ---------------------------------- | --------------------------- | --------------------------------------------------- |
494+ | ` Data.withSchema(schema) ` | ` (schema) → Codec ` | Create a type-safe codec from a TSchema definition |
495+ | ` Data.hashData(data) ` | ` (Data) → DatumHash ` | Hash PlutusData with blake2b-256 over CBOR encoding |
496+ | ` Data.hash(data) ` | ` (Data) → number ` | Hash value for equality comparison |
497+ | ` Data.toCBORHex(data) ` | ` (Data) → string ` | Encode raw PlutusData to CBOR hex |
498+ | ` Data.fromCBORHex(hex) ` | ` (string) → Data ` | Decode CBOR hex to raw PlutusData |
499+ | ` Data.toCBORBytes(data) ` | ` (Data) → Uint8Array ` | Encode raw PlutusData to CBOR bytes |
500+ | ` Data.fromCBORBytes(bytes) ` | ` (Uint8Array) → Data ` | Decode CBOR bytes to raw PlutusData |
501+ | ` Data.equals(a, b) ` | ` (Data, Data) → boolean ` | Deep equality check for PlutusData |
502+ | ` Data.constr(index, fields) ` | ` (bigint, Data[]) → Constr ` | Create a Constructor PlutusData |
503+ | ` Data.map(entries) ` | ` ([Data, Data][]) → Map ` | Create a Map PlutusData |
504+ | ` Data.list(items) ` | ` (Data[]) → List ` | Create a List PlutusData |
505+ | ` Data.int(value) ` | ` (bigint) → Int ` | Create an Integer PlutusData |
506+ | ` Data.bytearray(bytes) ` | ` (string) → ByteArray ` | Create a ByteArray PlutusData from hex string |
507+ | ` Data.isConstr(data) ` | ` (Data) → boolean ` | Type guard for Constr |
508+ | ` Data.isMap(data) ` | ` (Data) → boolean ` | Type guard for Map |
509+ | ` Data.isList(data) ` | ` (Data) → boolean ` | Type guard for List |
510+ | ` Data.isInt(data) ` | ` (Data) → boolean ` | Type guard for Integer |
511+ | ` Data.isBytes(data) ` | ` (Data) → boolean ` | Type guard for ByteArray |
512+ | ` Data.matchConstr(data, handlers) ` | ` (Data, handlers) → T ` | Pattern match on a Constr |
513+ | ` Data.matchData(data, handlers) ` | ` (Data, handlers) → T ` | Pattern match on any PlutusData |
514+ | ` DataEncoded ` | ` type ` | JSON-serializable representation of PlutusData |
515+ | ` DataError ` | ` class ` | Tagged error for Data encoding/decoding failures |
516+
318517## Next Steps
319518
320519<Cards >
0 commit comments