Build Cardano Transaction
Guide the user through building Cardano transactions step by step using their chosen off-chain SDK. Covers the full lifecycle: prerequisites, transaction construction, signing, submission, and verification on a testnet.
When to Use
- User wants to send ADA or native tokens to an address
- User wants to mint an NFT or fungible token
- User wants to interact with a deployed smart contract (lock, redeem, etc.)
- User wants to delegate stake to a pool or DRep
- User wants to register as a DRep or cast a governance vote
- User asks how to build, sign, or submit a Cardano transaction
- User asks which SDK to use for off-chain transaction building
- User is in Haskell and wants to build a Conway tx from an Aiken blueprint with cardano-ledger / haskell.nix / CHaP
When NOT to Use
- User wants to write or review on-chain validator logic -- use
write-validatororreview-contract - User is designing token metadata standards -- use
design-token - User has a failing transaction and needs help debugging -- use
debug-transaction - User wants to set up a local devnet or node infrastructure -- use
setup-devnet
Key Principles
Choose the right SDK for the job. Mesh SDK (TypeScript) and Evolution SDK (TypeScript) have the best documentation and highest-level APIs. PyCardano is best for Python shops. cardano-client-lib suits JVM projects needing fine control. Haskell services that share types with the node use cardano-ledger (not Mesh, not Atlas) and are built with haskell.nix + CHaP. Search
${CLAUDE_SKILL_DIR}/../../docs/sources/for the latest SDK comparison details.Always prototype on Preview testnet. Never build against mainnet first. Use the Cardano faucet to obtain test ADA. Set the network parameter explicitly in every code example.
UTxO selection matters. Cardano uses the EUTxO model. The SDK must select unspent outputs that cover the transaction value plus fees. Understand coin selection to avoid
ValueNotConservedUTxOerrors.Fees and change are computed, not guessed. All SDKs have fee estimation. Let the SDK calculate fees and construct change outputs automatically.
Transactions are deterministic. The same inputs and parameters always produce the same transaction. This enables dry-run testing before submission.
Collateral is required for Plutus interactions. Any transaction that executes a Plutus script must include collateral UTxOs containing only ADA.
Workflow
Step 1: Gather Parameters
Ask the user to specify or confirm:
| Parameter | Options | Default |
|---|---|---|
| SDK | mesh, evolution-sdk, pycardano, cardano-client-lib, tx3, cardano-ledger, apollo |
mesh |
| Transaction type | send-ada, mint-nft, mint-token, interact-with-contract, delegate-stake, register-drep, vote |
required |
| Network | preview, preprod, mainnet |
preview |
| Wallet | mnemonic, private key, browser wallet | mnemonic |
If the user does not specify an SDK, recommend Mesh SDK for TypeScript
projects, cardano-client-lib for Java/JVM, Apollo for Go, or
cardano-ledger for Haskell (see references/haskell-ledger.md).
Alternative paradigm with Tx3: Most SDKs above build transactions imperatively in
code. Tx3 takes a declarative route: you describe a protocol's transactions
in a .tx3 interface file and generate typed clients in TypeScript, Rust, Go, or
Python (an ABI/OpenAPI analogue for UTxO protocols). Reach for it when the same
protocol is consumed from several languages, or when you are publishing a protocol
for others to integrate. It is pre-1.0; for a single-language app the imperative SDKs
are the more battle-tested default.
Step 2: Search Bundled Documentation
Search the bundled documentation for relevant content:
${CLAUDE_SKILL_DIR}/../../docs/sources/evolution-sdk/- Evolution SDK docs${CLAUDE_SKILL_DIR}/../../docs/sources/mesh-sdk/- Mesh SDK docs${CLAUDE_SKILL_DIR}/../../docs/sources/mesh-sdk-packages/- Mesh SDK package docs${CLAUDE_SKILL_DIR}/../../docs/sources/pycardano/- PyCardano docs${CLAUDE_SKILL_DIR}/../../docs/sources/cardano-client-lib/- Cardano Client Lib docs (QuickTx API, blueprint codegen, backend providers). For a worked lock-and-spend cycle, read the Java programs under${CLAUDE_SKILL_DIR}/../../docs/sources/cardano-use-case-templates/<use-case>/offchain/ccl-java/-- they are.java, so a markdown-only search will miss them.${CLAUDE_SKILL_DIR}/../../docs/sources/tx3/- Tx3 docs${CLAUDE_SKILL_DIR}/../../docs/sources/chap/- CHaP cabal.project + haskell.nix inputMap${CLAUDE_SKILL_DIR}/../../docs/sources/haskell-nix/- flakes,--sha256on git deps${CLAUDE_SKILL_DIR}/../../docs/sources/iohk-nix/- crypto overlays${CLAUDE_SKILL_DIR}/../../docs/sources/cardano-ledger/- Conway tx types / phase-1${CLAUDE_SKILL_DIR}/../../docs/sources/aiken/- CIP-57plutus.jsonfromaiken build${CLAUDE_SKILL_DIR}/../../docs/sources/apollo/- Apollo (Go) builder:docs/**prose plus.goAPI source${CLAUDE_SKILL_DIR}/../../docs/sources/gouroboros/- gOuroboros (Go) ledger types Apollo builds on
Step 3: Set Up Prerequisites
For each SDK, ensure the user has the required environment:
Mesh SDK (TypeScript/JavaScript)
npm install @meshsdk/core
- Requires Node.js 18+
- Needs a blockchain provider (Blockfrost, Koios, or Ogmios)
- Blockfrost API key from https://blockfrost.io
Evolution SDK (TypeScript)
npm install @evolution-sdk/evolution
- Requires Node.js 18+ and TypeScript 5.0+
- Effect-TS based, type-safe composable API
- Built-in Blockfrost, Koios, Kupmios, and Maestro providers
- Works in Node.js and browser environments
PyCardano (Python)
pip install pycardano
- Requires Python 3.8+
- Needs a chain context (Blockfrost, Ogmios, or CardanoCliContext)
cardano-client-lib (Java)
<dependency>
<groupId>com.bloxbean.cardano</groupId>
<artifactId>cardano-client-lib</artifactId>
<version>0.7.2</version>
</dependency>
- Java/JVM library by BloxBean
- Good for fine-grained transaction control
Tx3 (declarative, multi-language)
Tx3 is not a library you install into one project — it is a toolchain plus a per-language runtime SDK. Setup has three parts:
# 1. Install the toolchain (provides trix, the compiler, and the LSP)
tx3up # see docs/sources/tx3/installation.mdx for the installer
tx3up show # verify installed components
# 2. Install the runtime SDK for your target language, e.g. TypeScript
npm install tx3-sdk # Rust: tx3-sdk crate · Go: go-sdk · Python: tx3-sdk
- Needs a TRP endpoint to resolve, sign, and submit —
trix devnetexposes a local one athttp://localhost:8164; for preview/preprod/mainnet point at a hosted TRP endpoint. - Needs the toolchain for whichever client language you generate (Node.js 18+, Rust 1.78+, Go 1.22+, or Python 3.10+).
- Search
${CLAUDE_SKILL_DIR}/../../docs/sources/tx3/for the language reference,trixcommands, and Cardano examples.
cardano-ledger (Haskell)
This path is a haskell.nix flake, not cabal on a system GHC. Full wiring
(CHaP stanza, inputMap, iohk-nix overlays, Aiken blueprint):
references/haskell-ledger.md. Short form:
# inside the haskell.nix dev shell
cabal update
cabal build all -O0
cabal.projectmust contain the CHaPrepositorystanza and a dualindex-state(Hackage +cardano-haskell-packages). Seedocs/sources/chap/README.md.- Flake input
CHaPon?ref=index-only, theninputMap = { "https://chap.intersectmbo.org/" = CHaP; }. - iohk-nix overlays
cryptoandhaskell-nix-crypto(CHaP README: needed forlibblst/plutus-core). source-repository-packagestanzas need a--sha256comment (docs/sources/haskell-nix/tutorials/source-repository-hashes.md).- Load scripts from Aiken
plutus.json(CIP-57). Datums/redeemers areplutus-txToData, not JSON.
Apollo (Go)
go get github.com/Salvionied/apollo/v2
- Needs a
backend.ChainContext(Blockfrost, Maestro, Ogmios, UTxORPC, or a fixed/cached backend) - Builds on gOuroboros ledger types, so
common.Addressand friends are shared across the Go stack - Always use the
/v2module path. It is the maintained line and what the mirror documents. The unsuffixedgithub.com/Salvionied/apollopath is feature-complete and no longer receives updates — when porting code off it, seedocs/v2_migration/MIGRATION.mdin the mirror. - The
/v2path is on a stable release line, sogo getresolves to a released tag rather than a pre-release or a commit off the default branch
Step 4: Build the Transaction
Provide step-by-step code for the chosen SDK and transaction type. Follow these patterns:
Send ADA Pattern
- Initialize the provider and wallet
- Create a transaction builder
- Add the payment output (recipient address + lovelace amount)
- Let the SDK handle coin selection, fee calculation, and change
- Sign with the wallet
- Submit to the network
- Log the transaction hash
Mint NFT / Token Pattern
- Initialize the provider and wallet
- Define the minting policy (time-locked or Plutus script)
- Prepare token metadata conforming to CIP-25 or CIP-68
- Create a transaction builder
- Add the minting action (policy, asset name, quantity)
- Add metadata to the transaction
- Sign with policy key + wallet key
- Submit and log the transaction hash
Interact with Contract Pattern
- Initialize the provider and wallet
- Load the Plutus script (from file or CIP-57 blueprint)
- For locking: build a tx that sends value to the script address with a datum
- For redeeming: query UTxOs at the script address, select the target, build a tx that spends it with the correct redeemer, include collateral
- Sign, submit, and verify
Delegate Stake Pattern
- Initialize the provider and wallet
- Create or retrieve the stake address
- Register the stake address (if not already registered -- costs 2 ADA deposit)
- Build a delegation certificate targeting the chosen pool ID
- Sign and submit
Register DRep / Vote Pattern
- Initialize the provider and wallet
- For DRep registration: build a DRep registration certificate with metadata anchor
- For voting: build a voting procedure targeting a governance action ID
- Sign and submit
Step 5: Explain the Transaction
After providing code, explain:
- What each part of the transaction does
- How coin selection works in this context
- What fees are expected
- What happens on-chain when this transaction is processed
Step 6: Common Pitfalls
Warn about these frequent issues:
- Insufficient ADA for min-UTxO: Every UTxO must hold a minimum amount of ADA (roughly 1-2 ADA depending on datum/token bundle size). The SDK usually handles this, but manual outputs can fail.
- Forgetting collateral: Plutus transactions require a collateral input. Use a UTxO with only ADA (no tokens).
- Wrong network: Addresses are network-specific. A Preview address will not work on Preprod or Mainnet.
- Stale UTxO set: If another transaction consumed your inputs between
query and submit, you get
BadInputsUTxO. Re-query and rebuild. - Token name encoding: Asset names are hex-encoded bytes. Ensure proper
encoding (e.g.,
Buffer.from("MyToken").toString("hex")). - Transaction size limit: Max 16 KB. Large token bundles or many inputs can exceed this. Split into multiple transactions if needed.
Step 7: Test on a testnet before mainnet
A transaction that type-checks can still fail at submission (min-UTxO, fees, collateral,
script evaluation). Always run it on a testnet first — and for Plutus-script flows, a local
Yaci DevKit devnet (setup-devnet) gives the fastest build→submit→confirm loop.
- Get test ADA from the Cardano faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/
- Run the transaction code against Preview or Preprod
- Verify on a block explorer (Preview: https://preview.cardanoscan.io · Preprod: https://preprod.cardanoscan.io)
- Check the transaction hash matches expected outputs
- For minting: verify the token appears in the wallet
SDK Quick Reference
Mesh SDK -- Transaction Builder
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<BLOCKFROST_KEY>");
const txBuilder = new MeshTxBuilder({ fetcher: provider, submitter: provider });
// Build, sign, submit pattern
const unsignedTx = await txBuilder
.txOut(recipientAddress, [{ unit: "lovelace", quantity: "5000000" }])
.changeAddress(senderAddress)
.selectUtxosFrom(utxos)
.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
Evolution SDK -- Composable Builder
import { Address, Assets, 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 tx = await client
.newTx()
.payToAddress({
address: Address.fromBech32("addr_test1..."),
assets: Assets.fromLovelace(5_000_000n)
})
.build()
const signed = await tx.sign()
const txHash = await signed.submit()
PyCardano -- TransactionBuilder
from pycardano import TransactionBuilder, TransactionOutput, Address
builder = TransactionBuilder(context)
builder.add_input_address(sender_address)
builder.add_output(TransactionOutput(recipient, 5_000_000))
signed_tx = builder.build_and_sign([signing_key], change_address=sender_address)
context.submit_tx(signed_tx)
cardano-client-lib -- QuickTx
BackendService backendService = new BFBackendService(
"https://cardano-preprod.blockfrost.io/api/v0/", "<PROJECT_ID>");
QuickTxBuilder quickTxBuilder = new QuickTxBuilder(backendService);
Tx tx = new Tx()
.payToAddress(receiver, Amount.ada(1.5))
.from(sender.baseAddress());
TxResult result = quickTxBuilder.compose(tx)
.withSigner(SignerProviders.signerFrom(sender))
.completeAndWait();
Spending from a Plutus script uses ScriptTx and attaches the validator inline --
no reference script needs to be published first:
ScriptTx scriptTx = new ScriptTx()
.collectFrom(List.of(utxo), redeemer)
.payToAddress(receiver, utxo.getAmount())
.attachSpendingValidator(plutusScript);
TxResult result = quickTxBuilder.compose(scriptTx)
.feePayer(sender.baseAddress())
.withSigner(SignerProviders.signerFrom(sender)) // signs the tx
.withRequiredSigners(sender.getBaseAddress()) // satisfies must_be_signed_by
.completeAndWait();
Full guide -- datum encoding, minting, collateral: ${CLAUDE_SKILL_DIR}/references/cclib-quicktx.md.
Tx3 -- Declarative Interface + Typed Client
Tx3 splits the work in two. First, describe the transaction once in a .tx3
file (this is the protocol interface, language-agnostic):
party Sender;
party Receiver;
tx transfer(quantity: Int) {
input source {
from: Sender,
min_amount: Ada(quantity),
}
output {
to: Receiver,
amount: Ada(quantity),
}
output {
to: Sender,
amount: source - Ada(quantity) - fees,
}
}
Then generate a typed client and drive the lifecycle from your app (TypeScript shown; Rust/Go/Python clients are generated the same way):
trix codegen --plugin ts-client # emits a typed client from the .tx3 interface
import { Client } from "./gen/transfer";
import { Party, Ed25519Signer } from "tx3-sdk";
const client = new Client({ endpoint: "http://localhost:8164" }, "local")
.withSender(Party.signer(Ed25519Signer.fromHex("addr_test1...", "deadbeef...")))
.withReceiver(Party.address("addr_test1..."));
// Each `tx` becomes a typed method; the lifecycle is resolve → sign → submit
const status = await client
.transfer({ quantity: 10_000_000n })
.resolve()
.then((r) => r.sign())
.then((s) => s.submit())
.then((sub) => sub.waitForConfirmed());
The resolver (reached over TRP) does coin selection, fee calculation, and change —
the .tx3 file declares intent, not the concrete UTxOs.
Apollo -- Fluent Builder (Go)
Verified to compile against apollo/v2 at v2.0.1 (2026-08-19). The builder is
fluent, but the steps that can fail return (*Apollo, error) rather than a bare
*Apollo — AddInputAddressFromBech32 and PayToAddressBech32 among them — so
handle the error and re-assign at each of those:
import (
apollo "github.com/Salvionied/apollo/v2"
"github.com/Salvionied/apollo/v2/backend/blockfrost"
)
cc := blockfrost.NewBlockFrostChainContext(
"https://cardano-preprod.blockfrost.io/api/v0", 0, projectID)
b, err := apollo.New(cc).AddInputAddressFromBech32(senderBech32)
if err != nil { return err }
b, err = b.PayToAddressBech32(recipientBech32, 10_000_000)
if err != nil { return err }
b, err = b.Complete() // coin selection, fee calculation, balancing
if err != nil { return err }
Methods that only mutate builder state — AddLoadedUTxOs, RegisterDRep,
AddRequiredSigner — return a bare *Apollo and do chain, recording any error
internally for Complete to report. Start from doc.go in a mirrored package
for the overview, then Grep a method name in
${CLAUDE_SKILL_DIR}/../../docs/sources/apollo/ for its signature and doc
comment.
Then SetWalletFromMnemonic + Sign + Submit for a signed submission, or
GetTxCbor to hand the CBOR to an external signer. The mirror's docs/
directory carries worked examples for staking, governance, and Plutus V3.
References
references/sdk-comparison.md-- detailed SDK comparison tablereferences/haskell-ledger.md-- Aiken + cardano-ledger + CHaP + haskell.nixSearch
${CLAUDE_SKILL_DIR}/../../docs/sources/for CIP-25, CIP-68 metadata standardsCardano Developer Portal: https://developers.cardano.org
Mesh SDK docs: https://meshjs.dev
Evolution SDK docs: https://evolution-sdk.dev
PyCardano docs: https://pycardano.readthedocs.io
Tx3 docs: https://docs.txpipe.io/tx3
Apollo docs: https://pkg.go.dev/github.com/Salvionied/apollo/v2