Evolution SDK
Encoding

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:

TypeTypeScriptUse For
IntegerbigintAmounts, indices, timestamps, quantities
ByteArrayUint8ArrayHashes, addresses, policy IDs, asset names
Constructor{ index: bigint, fields: Data[] }Variants, tagged unions, structured data
MapMap<Data, Data>Metadata, key-value stores
ListReadonlyArray<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 : .. = 45000000000000000n

Byte 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 structure

Equality 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  = ..(, )
// true

Real-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 datum

CIP-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.

Next Steps