PlutusData
On-chain data structures for Cardano smart contracts
PlutusData
PlutusData is the serialization format for all on-chain data in Cardano smart contracts. Every datum attached to a UTxO, every redeemer that unlocks a script, and every parameter passed to a validator must be encoded as PlutusData.
The Evolution SDK's Data module gives you type-safe PlutusData creation without touching raw CBOR bytes.
The Five Types
PlutusData consists of five primitive types:
| Type | TypeScript | Use For |
|---|---|---|
| Integer | bigint | Amounts, indices, timestamps, quantities |
| ByteArray | Uint8Array | Hashes, addresses, policy IDs, asset names |
| Constructor | { index: bigint, fields: Data[] } | Variants, tagged unions, structured data |
| Map | Map<Data, Data> | Metadata, key-value stores |
| List | ReadonlyArray<Data> | Arrays of values |
Quick Start
Create PlutusData using TypeScript primitives:
import { , , } from "@evolution-sdk/evolution"
// Integer (bigint)
const : . = 5000000n
// ByteArray (Uint8Array)
const = .("HOSKY")
const = .("a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8")
// Constructor (variant with fields)
const = .(0n, []) // variant 0, no fields
// Map (key-value pairs)
const = .([
[.("name"), .("My NFT")],
[.("image"), .("ipfs://Qm...")]
])
// List (array)
const : . = [100n, 200n, 300n]Integers
Use bigint directly—no wrapper needed:
import { , , } from "@evolution-sdk/evolution"
// Lovelace amounts
const : . = 170000n
const : . = 2000000n
// Token quantities
const : . = 1n
const : . = 1000000n
// Negative values supported
const : . = -500n
// Large numbers
const : . = 45000000000000000nByte Arrays
Raw bytes for hashes, addresses, and binary data:
import { , , } from "@evolution-sdk/evolution"
// Transaction hash (32 bytes)
const = .(
"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
)
// Policy ID (28 bytes)
const = .(
"1234567890abcdef1234567890abcdef1234567890abcdef12345678"
)
// Asset name (readable string)
const = .("MyToken")
// Empty byte array (ada-only policyId)
const = new ()When to use Bytes.fromHex vs Text.toBytes:
Bytes.fromHex: For hashes, policy IDs, credential hashes (hexadecimal data)Text.toBytes: For asset names, metadata values (human-readable strings)
Constructors
Tagged unions representing variants or structured data:
import { , , } from "@evolution-sdk/evolution"
// Simple variant (no data)
const = .(0n, [])
const = .(1n, [])
// Variant with single field
const = .(0n, [
.("abc123def456abc123def456abc123def456abc123def456abc123de")
])
const = .(1n, [
.("def456abc123def456abc123def456abc123def456abc123def456ab")
])
// Multiple fields
const = .(0n, [
.("a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"), // tx hash
2n // output index
])Constructor index determines which variant you're creating. Your Plutus validator defines what each index means.
Maps
Key-value pairs where both keys and values are PlutusData:
import { , , } from "@evolution-sdk/evolution"
// NFT metadata
const = .([
[.("name"), .("CryptoKitty #1234")],
[.("image"), .("ipfs://QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco")],
[.("description"), .("A rare cryptokitty with rainbow fur")]
])
// Nested maps
const = .([
[.("name"), .("MyToken")],
[.("ticker"), .("MTK")],
[.("decimals"), 6n],
[.("properties"), .([
[.("mintable"), 1n], // boolean as 0/1
[.("burnable"), 1n]
])]
])Lists
Ordered arrays of PlutusData:
import { , , } from "@evolution-sdk/evolution"
// List of integers
const : . = [100n, 250n, 500n, 1000n]
// List of byte arrays (hashes)
const : . = [
.("abc123def456abc123def456abc123def456abc123def456abc123de"),
.("def456abc123def456abc123def456abc123def456abc123def456ab"),
.("123456789abc123456789abc123456789abc123456789abc12345678")
]
// List of constructors
const : . = [
.(0n, []), // Claim
.(1n, []), // Cancel
.(2n, [5000000n]) // PartialClaim(amount)
]CBOR Encoding
Convert PlutusData to CBOR for blockchain submission:
import { , , } from "@evolution-sdk/evolution"
const = .(0n, [
.([
[.("beneficiary"), .("addr1...")],
[.("deadline"), 1735689600000n]
]),
5000000n, // amount
1n // version
])
// Encode to hex string
const = .()
// "d8799fa2646265..."
// Encode to bytes
const = .()
// Uint8Array [216, 121, 159, ...]
// Decode from CBOR
const = .()
// Returns original PlutusData structureEquality Comparison
Check if two PlutusData structures are equal:
import { , , } from "@evolution-sdk/evolution"
const = .([
[.("name"), .("Alice")],
[.("age"), 30n]
])
const = .([
[.("name"), .("Alice")],
[.("age"), 30n]
])
// Deep equality check
const = .(, )
// trueReal-World Examples
Escrow Datum
import { , , } from "@evolution-sdk/evolution"
// Escrow locked until deadline
const = .(0n, [
.("abc123def456abc123def456abc123def456abc123def456abc123de"), // beneficiary
1735689600000n, // deadline (Unix timestamp)
10000000n // locked lovelace amount
])
const = .()
// Attach to UTxO as inline datumCIP-68 NFT Metadata
import { , , } from "@evolution-sdk/evolution"
// Reference NFT metadata (label 100)
const = .([
[.("name"), .("SpaceAce #4242")],
[.("image"), .("ipfs://QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco")],
[.("rarity"), .("legendary")],
[.("attributes"), .([
[.("class"), .("explorer")],
[.("power"), 9000n]
])]
])
const = .(0n, [
,
1n, // version
[] // extra fields
])Redeemer with Multiple Actions
import { , , } from "@evolution-sdk/evolution"
// Action variants
const = .(0n, [])
const = .(1n, [])
const = .(2n, [
1735776000000n // new deadline
])
// Use in transaction
const = Multi-Sig Validator Redeemer
import { , , } from "@evolution-sdk/evolution"
const = .(0n, [
// Required signers (list of key hashes)
[
.("abc123def456abc123def456abc123def456abc123def456abc123de"),
.("def456abc123def456abc123def456abc123def456abc123def456ab")
] as .,
2n // threshold (2 of N)
])When to Use PlutusData Directly
Use the Data module directly when:
- Quick prototyping or testing
- Working with dynamic data structures
- Debugging CBOR encoding issues
- Building tooling or explorers
For production smart contract integration, use TSchema for type-safe schema definitions with automatic validation.