Skip to main content

Native Scripts

Native scripts are lightweight validators that don't require Plutus. They check simple conditions — key signatures, time constraints, or combinations of both. Use them for time-locked vesting, multi-sig wallets, and simple minting policies.

No script evaluation costs, no collateral required, smaller transactions.

Script Types

TypeWhat It ChecksUse Case
ScriptPubKeyA specific key signed the transactionSingle-signer authorization
InvalidBeforeTransaction is after a slotTime-locked release
InvalidHereafterTransaction is before a slotDeadline enforcement
ScriptAllALL sub-scripts passMulti-sig (all must sign)
ScriptAnyANY sub-script passesMulti-sig (one must sign)
ScriptNOfKN of K sub-scripts passM-of-N multi-sig

Building Native Scripts

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

// Single key requirement
const singleSigner = NativeScripts.makeScriptPubKey(
Bytes.fromHex("abc123def456abc123def456abc123def456abc123def456abc123de")
)

// Time-lock: can't spend before slot 100000
const timeLock = NativeScripts.makeInvalidBefore(100000n)

// Deadline: can't spend after slot 200000
const deadline = NativeScripts.makeInvalidHereafter(200000n)

Multi-Sig: All Must Sign

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

const keyHash1 = Bytes.fromHex("abc123def456abc123def456abc123def456abc123def456abc123de")
const keyHash2 = Bytes.fromHex("def456abc123def456abc123def456abc123def456abc123def456ab")
const keyHash3 = Bytes.fromHex("a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8")

const multiSig = NativeScripts.makeScriptAll([
NativeScripts.makeScriptPubKey(keyHash1),
NativeScripts.makeScriptPubKey(keyHash2),
NativeScripts.makeScriptPubKey(keyHash3),
])

Multi-Sig: Any Can Sign

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

const keyHash1 = Bytes.fromHex("abc123def456abc123def456abc123def456abc123def456abc123de")
const keyHash2 = Bytes.fromHex("def456abc123def456abc123def456abc123def456abc123def456ab")

const anyOf = NativeScripts.makeScriptAny([
NativeScripts.makeScriptPubKey(keyHash1),
NativeScripts.makeScriptPubKey(keyHash2),
])

Multi-Sig: M-of-N

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

const keyHash1 = Bytes.fromHex("abc123def456abc123def456abc123def456abc123def456abc123de")
const keyHash2 = Bytes.fromHex("def456abc123def456abc123def456abc123def456abc123def456ab")
const keyHash3 = Bytes.fromHex("a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8")

// 2-of-3 multi-sig
const twoOfThree = NativeScripts.makeScriptNOfK(2n, [
NativeScripts.makeScriptPubKey(keyHash1),
NativeScripts.makeScriptPubKey(keyHash2),
NativeScripts.makeScriptPubKey(keyHash3),
])

Time-Locked Vesting

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

const beneficiary = Bytes.fromHex("abc123def456abc123def456abc123def456abc123def456abc123de")

const vestingScript = NativeScripts.makeScriptAll([
NativeScripts.makeScriptPubKey(beneficiary),
NativeScripts.makeInvalidBefore(50000000n),
])

Minting with Native Scripts

import { Assets, NativeScripts, Bytes, preprod, Client } from "@evolution-sdk/evolution"

const client = Client.make(preprod)
.withBlockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0",
projectId: process.env.BLOCKFROST_API_KEY!
})
.withSeed({ mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 })

const myKeyHash = Bytes.fromHex("abc123def456abc123def456abc123def456abc123def456abc123de")

const mintingPolicy = NativeScripts.makeScriptPubKey(myKeyHash)
const script = new NativeScripts.NativeScript({ script: mintingPolicy })

declare const policyId: string

let assets = Assets.fromLovelace(0n)
assets = Assets.addByHex(assets, policyId, "4d79546f6b656e", 1000n)

const tx = await client
.newTx()
.mintAssets({ assets })
.attachScript({ script })
.build()

const signed = await tx.sign()
await signed.submit()

Utility Functions

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

const keyHash1 = Bytes.fromHex("abc123def456abc123def456abc123def456abc123def456abc123de")
const keyHash2 = Bytes.fromHex("def456abc123def456abc123def456abc123def456abc123def456ab")

const script = NativeScripts.makeScriptAll([
NativeScripts.makeScriptPubKey(keyHash1),
NativeScripts.makeScriptPubKey(keyHash2),
NativeScripts.makeInvalidBefore(100000n),
])

// Count minimum required signers
const count = NativeScripts.countRequiredSigners(script)

// Extract all key hashes from the script tree
const keyHashes = NativeScripts.extractKeyHashes(script)

// Serialize to CBOR
const cbor = NativeScripts.toCBORHex(
new NativeScripts.NativeScript({ script })
)

// Convert to JSON
const json = NativeScripts.toJSON(script)

Native Scripts vs Plutus Scripts

Native ScriptsPlutus Scripts
ComplexitySimple conditions onlyArbitrary logic
Execution costNone (free)Memory + CPU units
CollateralNot requiredRequired
Transaction sizeSmallerLarger (script included)
RedeemerNot neededRequired
Use casesMulti-sig, time-locks, simple mintingDeFi, auctions, complex validation

Next Steps