Getting Started with Aiken Smart Contracts and Mesh SDK
Build your first Cardano smart contract with Aiken and interact with it using the Mesh TypeScript blockchain SDK for dApp development.
Aiken is a functional programming language designed specifically for Cardano smart contracts. Combined with the Mesh Cardano SDK, you can write, deploy, and interact with Cardano smart contracts using familiar JavaScript Web3 tooling.
This tutorial builds a complete "Hello World" Cardano smart contract—you'll write the on-chain validator in Aiken, then use the Mesh TypeScript blockchain SDK to create transactions that lock and unlock assets in your Cardano dApp development.
Resources:
How Do You Install Aiken?
Linux/MacOS - Use the aikup installer:
curl -sSfL https://install.aiken-lang.org | bash
aikupAll platforms - Install from source via Cargo (requires Rust):
cargo install aikenVerify your installation:
aiken -VSee the Aiken installation guide for troubleshooting.
How Do You Write an Aiken Smart Contract?
Create a new Aiken project:
aiken meshjs/hello_world
cd hello_world
aiken checkCreate validators/hello_world.ak with the validator logic:
use aiken/hash.{Blake2b_224, Hash}
use aiken/list
use aiken/transaction.{ScriptContext}
use aiken/transaction/credential.{VerificationKey}
type Datum {
owner: Hash<Blake2b_224, VerificationKey>,
}
type Redeemer {
msg: ByteArray,
}
validator {
fn hello_world(datum: Datum, redeemer: Redeemer, context: ScriptContext) -> Bool {
let must_say_hello =
redeemer.msg == "Hello, World!"
let must_be_signed =
list.has(context.transaction.extra_signatories, datum.owner)
must_say_hello && must_be_signed
}
}This validator enforces two conditions:
- The redeemer message must be "Hello, World!"
- The transaction must be signed by the datum owner
Compile the contract:
aiken buildThis generates plutus.json—a CIP-0057 Plutus blueprint containing your compiled validator.
How Do You Lock Assets at the Script Address?
Set up your frontend (see Next.js guide) and install dependencies:
npm install cborCopy plutus.json to a data folder and import the required packages:
import {
resolvePlutusScriptAddress,
MeshTxBuilder,
KoiosProvider,
resolveDataHash,
resolvePaymentKeyHash,
} from "@meshsdk/core";
import type { PlutusScript, Data } from "@meshsdk/core";
import { CardanoWallet, useWallet } from "@meshsdk/react";
import plutusScript from "../data/plutus.json";
import cbor from "cbor";Load the compiled contract and resolve its address:
const script: PlutusScript = {
code: cbor
.encode(Buffer.from(plutusScript.validators[0].compiledCode, "hex"))
.toString("hex"),
version: "V2",
};
const scriptAddress = resolvePlutusScriptAddress(script, 0);The CBOR encoding converts Aiken's flat format to the format expected by Cardano serialization libraries in the Mesh Cardano SDK.
Build the locking transaction—this sends ADA to the script with a datum containing the owner's public key hash:
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const hash = resolvePaymentKeyHash((await wallet.getUsedAddresses())[0]);
const datum: Data = {
alternative: 0,
fields: [hash],
};
const txBuilder = new MeshTxBuilder({
fetcher: koios,
});
const unsignedTx = await txBuilder
.txOut(scriptAddress, [{ unit: "lovelace", quantity: "5000000" }])
.txOutDatumHashValue(datum)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos)
.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);How Do You Unlock Assets from the Script?
First, find the UTxO containing your locked assets:
async function _getAssetUtxo({ scriptAddress, asset, datum }) {
const utxos = await koios.fetchAddressUTxOs(scriptAddress, asset);
const dataHash = resolveDataHash(datum);
let utxo = utxos.find((utxo: any) => {
return utxo.output.dataHash == dataHash;
});
return utxo;
}Build the unlock transaction with the correct redeemer message:
const scriptAddress = resolvePlutusScriptAddress(script, 0);
const address = (await wallet.getUsedAddresses())[0];
const hash = resolvePaymentKeyHash(address);
const datum: Data = {
alternative: 0,
fields: [hash],
};
const assetUtxo = await _getAssetUtxo({
scriptAddress: scriptAddress,
asset: "lovelace",
datum: datum,
});
const redeemer: Data = { alternative: 0, fields: ['Hello, World!'] };
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const collateral = await wallet.getCollateral();
const txBuilder = new MeshTxBuilder({
fetcher: koios,
});
// create the unlock asset transaction
const unsignedTx = await txBuilder
.spendingPlutusScriptV2()
.txIn(assetUtxo.input.txHash, assetUtxo.input.outputIndex)
.txInDatumValue(datum)
.txInRedeemerValue(redeemer)
.txInScript(script.code)
.txOut(address, assetUtxo.output.amount)
.requiredSignerHash(hash)
.txInCollateral(
collateral[0].input.txHash,
collateral[0].input.outputIndex,
collateral[0].output.amount,
collateral[0].output.address,
)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos)
.complete();
const signedTx = await wallet.signTx(unsignedTx, true);
const txHash = await wallet.submitTx(signedTx);Key components of the unlock transaction:
spendingPlutusScriptV2()— Indicates a Plutus V2 script spendtxInDatumValue— Provides the original datumtxInRedeemerValue— Provides "Hello, World!" to satisfy the validatorrequiredSignerHash— Ensures the owner signs the transaction
What Should You Explore Next?
- View the complete source code
- Learn more at the Aiken documentation
- Explore building a vesting contract
- Read about smart contract transaction patterns
How to Build NFT Marketplace Transactions with Cardano Smart Contracts
Build Cardano smart contract transactions for an NFT marketplace using the Mesh TypeScript blockchain SDK for dApp development.
How to Run Standalone Cardano Scripts with TypeScript
Execute TypeScript scripts directly to interact with the Cardano blockchain using the Mesh Cardano SDK and tsx for JavaScript Web3 development.