Evolution SDK
Smart contracts

Datums

Attach data to script-locked UTxOs

Datums

Datums are the data payloads attached to UTxOs at script addresses. When you lock funds to a smart contract, the datum carries the state your validator needs — beneficiary addresses, deadlines, token quantities, or any structured data your contract logic requires.

Datum Options

Evolution SDK supports two ways to attach datums to outputs:

TypeDescriptionWhen to Use
Inline DatumData stored directly in the UTxORecommended for most use cases (Plutus V2+)
Datum HashOnly a hash stored on-chain; full datum provided when spendingLegacy Plutus V1 contracts

Inline Datums

Inline datums embed the full data in the output. The spending transaction can read it directly without needing to provide the datum separately:

import { , , , ,  } from "@evolution-sdk/evolution"

const  = ({
  : "preprod",
  : { : "blockfrost", : "https://cardano-preprod.blockfrost.io/api/v0", : ..! },
  : { : "seed", : ..!, : 0 }
})

// Simple inline datum
const  = await 
  .()
  .({
    : .("addr_test1wrm9x2dgvdau8vckj4duc89m638t8djmluqw5pdrFollw8qnmqsyu"),
    : .(10_000_000n),
    : new .({ : .(0n, [5000000n, 1735689600000n]) })
  })
  .()

Datum Hashes

Datum hashes store only a 32-byte hash in the output. The full datum must be provided when spending:

import { Address, Assets, Data, createClient } from "@evolution-sdk/evolution"

const client = createClient({
  network: "preprod",
  provider: { type: "blockfrost", baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY! },
  wallet: { type: "seed", mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 }
})

// Compute datum hash from PlutusData
const datum = Data.constr(0n, [5000000n])
const datumHash = Data.hashData(datum)

const tx = await client
  .newTx()
  .payToAddress({
    address: Address.fromBech32("addr_test1wrm9x2dgvdau8vckj4duc89m638t8djmluqw5pdrFollw8qnmqsyu"),
    assets: Assets.fromLovelace(10_000_000n),
    datum: datumHash // DatumHash returned by hashData
  })
  .build()

Type-Safe Datums with TSchema

For production contracts, define your datum structure with TSchema to get compile-time type checking and automatic CBOR encoding:

import { , ,  } from "@evolution-sdk/evolution"

// Define datum schema matching your validator
const  = .({
  : .,
  : .,
  : .
})

type  = typeof .
const  = .()

// Create type-safe datum
const :  = {
  : .("abc123def456abc123def456abc123def456abc123def456abc123de"),
  : 1735689600000n,
  : 10_000_000n
}

// Encode to PlutusData for use in transactions
const  = .()

Constructing Complex Datums

Variant Datums

For datums with multiple possible shapes:

import { , ,  } from "@evolution-sdk/evolution"

const  = .({
  : {
    : .,
    : .
  },
  : {
    : .,
    : .,
    : .
  },
  : {}
})

type  = typeof .

const :  = {
  : { : 1500000n, : 100n }
}

const :  = {
  : { : 2000000n, : 50n, : 10n }
}

Using Raw PlutusData

For quick prototyping without schemas:

import { , ,  } from "@evolution-sdk/evolution"

// Constructor with fields
const  = .(0n, [
  .("abc123def456abc123def456abc123def456abc123def456abc123de"),
  1735689600000n,
  .([
    [.("name"), .("My NFT")],
    [.("image"), .("ipfs://Qm...")]
  ])
])

Reading Datums from UTxOs

When querying UTxOs, inline datums are available directly on the UTxO object:

import { , , , ,  } from "@evolution-sdk/evolution"

const  = ({
  : "preprod",
  : { : "blockfrost", : "https://cardano-preprod.blockfrost.io/api/v0", : ..! },
  : { : "seed", : ..!, : 0 }
})

// Query UTxOs at a script address
const  = .("addr_test1wrm9x2dgvdau8vckj4duc89m638t8djmluqw5pdrFollw8qnmqsyu")
const  = await .()

for (const  of ) {
  if (.) {
    // datumOption is InlineDatum or DatumHash
    .("UTxO has datum attached")
  }
}

Best Practices

  • Use inline datums for new contracts — they're simpler and don't require datum lookup when spending
  • Use TSchema for production — compile-time type checking prevents encoding mistakes
  • Match your validator exactly — field names and order in TSchema must match your Plutus type definitions
  • Test round-trips — verify that encoding and decoding your datum produces identical results

Next Steps