Your First Aleo Contract in Leo: Mappings, Records, and Transitions

TL;DR

This tutorial is written against the Aleo reference primer fetched on 2026-05-20 and the mainnet snarkVM README. The Leo documentation URLs in the primer resolve to “Page Not Found,” so this guide is intentionally strict about what is and is not verifiable.

What is safe to say:

What is not safe to do from the provided primer:

So this is a production-honest tutorial: it explains how to design your first Aleo contract correctly, what invariants matter, and where you must verify against your local installation/compiler version before shipping.


What version this tutorial is written against, and why that matters

The first thing a working developer should know is whether the examples in a tutorial can be copied verbatim. In this case, the answer is no, and that is not a defect of Aleo so much as a limitation of the source material provided here.

The verified references available in the primer are:

From the snarkVM README, the following are verifiable:

Verifiable snippets from the README include:

[dependencies]
snarkvm = "major.minor.patch"

and:

git clone --branch staging --single-branch https://github.com/ProvableHQ/snarkVM.git
cd snarkVM
cargo build --release

That is useful for environment context, but it does not give us authoritative Leo program syntax. Because of that, this tutorial does not present copy-paste Leo code. Instead, it teaches the contract design you should implement once you check the exact syntax in your local toolchain.

That may sound conservative, but for zero-knowledge systems it is the correct posture. Small syntax differences can reflect larger semantic differences:

In other words: if you are evaluating whether to ship on Aleo, the right first step is not memorizing syntax. It is understanding the state model.

For the rest of this tutorial, I will describe the three concepts in a way that remains valid even if the surface syntax changes:

That mental model is the durable part.


The Aleo mental model: transitions, mappings, and records

If you come from EVM development, it is tempting to look for direct analogies:

Those analogies are helpful, but incomplete. Aleo’s design is shaped by zero-knowledge proving and private ownership.

Transitions

A transition is the executable action in your program. Conceptually, a transition:

  1. takes some inputs,
  2. proves that the requested state change is valid,
  3. updates public/shared state and/or private state,
  4. emits outputs that can be consumed later.

The important shift is that a transition is not just “run some code.” It is “run code in a way that can be proven.” That means every branch, arithmetic constraint, ownership check, and state dependency should be designed with proving costs and privacy boundaries in mind.

For a first contract, think of transitions like:

The exact names and syntax are compiler-specific. The design principle is not.

Mappings

A mapping is the part of your program state that is naturally shared and addressable by key. This is where you keep data that many users or observers may need to reference.

Common uses:

Mappings are appropriate when the system needs a canonical answer to “what is the current value for key K?”

For your first Aleo contract, a mapping is usually the easiest place to put minimal global state. Examples at the design level:

Again, these are conceptual examples, not guaranteed Leo syntax.

Records

A record is the Aleo concept most developers need to pause on. The easiest way to think about a record is:

a privately owned state object that can carry data and is intended to move between users or be consumed by later transitions.

If you know UTXO systems or note-based privacy systems, that is a closer analogy than account storage.

Records are useful when you want a user to hold data privately, such as:

A record generally answers the question: “what private object does this user control that allows them to perform the next step?”

Why Aleo needs both mappings and records

Aleo is most interesting when you use both.

Mappings are good for:

Records are good for:

Transitions connect them:

That pattern is the heart of many Aleo applications.


A concrete first contract design: private vouchers with public spend protection

Because we cannot verify current Leo syntax from the primer, the best way to learn is through a contract design that is simple but realistic. A good first contract is a private voucher system.

Why this example works:

Goal

We want a program that lets an authorized issuer create vouchers. A user can privately hold a voucher and later redeem it. The chain should prevent the same voucher from being redeemed twice.

State model

Conceptually, the program has:

Shared state in mappings

Private state in records

Transition set

At minimum, the contract design needs three transitions.

1. Initialize or configure issuer authority

Purpose:

Conceptually:

Things to verify in your local version:

2. Issue voucher

Purpose:

Inputs at the design level:

Behavior:

Questions you must resolve locally:

3. Redeem voucher

Purpose:

Inputs:

Behavior:

This transition demonstrates the classic Aleo composition:

Data model decisions

Even before syntax, you need to decide what lives where.

Put in a mapping only what must be shared

Every shared value increases your public or globally coordinated state footprint. So keep mappings minimal.

Good mapping candidates:

Bad mapping candidates for a privacy-first design:

Put in records what belongs to the user

A record should carry the data that the user must later prove control over.

Good record fields:

Be careful with fields that create unwanted correlation. If every voucher includes a public-looking sequential ID that later becomes visible during redemption, then privacy can degrade. You should think through whether the voucher ID is:

Invariants to define before implementation

Aleo contracts become safer when you state the invariants first. For this voucher example:

  1. Only authorized issuers can create vouchers.
  2. A voucher can be redeemed at most once.
  3. Only the record owner can redeem a voucher.
  4. Redemption preserves the intended amount or entitlement.
  5. No transition can forge issuer authority or bypass the redeemed mapping check.

These invariants are more important than syntax. If your eventual Leo code does not clearly enforce them, the design is incomplete.

A pseudo-interface, intentionally not Leo syntax

Because the primer does not verify current Leo syntax, here is a conceptual interface only:

Treat this as a design checklist, not code.

When you translate it to Leo, verify locally:


How to reason about privacy and correctness before you write Leo

Aleo development gets easier when you separate two concerns:

  1. correctness: can invalid state transitions be ruled out?
  2. privacy: does the contract reveal only what it must?

A first contract often fails not because the arithmetic is hard, but because the privacy boundary is drawn poorly.

Correctness in a ZK setting

In a normal smart contract, correctness is “the VM executed the checks.” In a ZK system, correctness is “the transition’s constraints and state rules make invalid execution unprovable or unacceptable.”

For the voucher design, correctness means:

This is why mappings matter. A record alone may represent private ownership, but without some shared anti-replay mechanism, the system can be vulnerable to double use of the same entitlement. The shared mapping acts like the canonical memory of what has already been consumed.

Privacy tradeoffs

There is no such thing as “fully private by default” without design choices. Even with records, your transition shape may leak more than you intend.

For example:

A practical design question is:

what is the minimum public information needed to prevent replay and enforce policy?

Sometimes a public redeemed flag keyed by a hidden commitment-derived identifier is enough. Sometimes your application needs public IDs for business reasons. The right answer depends on the product, but the contract should make the leak explicit.

Access control deserves extra care

Aleo developers sometimes focus on private ownership and forget that issuer/admin authority is equally critical.

For the voucher contract, you need to decide:

In many first contracts, simple is better:

Do not optimize authority management until the basic invariant is working.

Plan for lifecycle, not just one transition

A record is almost never useful in isolation. Its value comes from lifecycle.

For a first Aleo contract, write down the lifecycle in plain language:

  1. Admin configures issuer authority.
  2. Issuer creates a voucher record for a user.
  3. User stores that record locally.
  4. User later submits a redemption transition.
  5. The program marks the voucher as redeemed.
  6. The voucher record is consumed and cannot be reused.

If you cannot explain the lifecycle without syntax, you are not ready to implement it with syntax.

Think about failure cases

A production-minded design also asks:

Some of these are application-level choices, not mandatory protocol features. But if you are evaluating whether to ship, they determine whether Aleo’s record model matches your product requirements.


Translating the design into Leo safely

This is the part where many tutorials would dump code. I will not do that here because the Leo syntax pages in the primer are unavailable. Instead, I will show you exactly what to verify when you open your local Leo installation or compiler docs.

Step 1: Verify how a program declares records

You need to confirm:

Your first implementation should define one small record type only. Keep it minimal:

Add optional metadata later.

Step 2: Verify how a program declares mappings

You need to confirm:

For the voucher example, a single redeemed mapping is enough to learn the model. Avoid multiple mappings until you are clear on initialization and updates.

Step 3: Verify transition declaration and I/O rules

You need to check:

For a first contract, you want one transition that returns a record and one that consumes it. That gives you the full lifecycle.

Step 4: Verify state access restrictions inside transitions

This is where compiler-version differences matter most.

You must confirm locally:

Do not assume a familiar imperative programming model. Provable languages often restrict control flow, mutation patterns, or built-in operations.

Step 5: Verify deployment, proving, and execution commands

The primer does not provide Leo CLI commands. So you must verify against your local installation/compiler version for:

What is verifiable from the available primer is that the broader Aleo stack uses snarkVM and that Rust-based tooling exists in the ecosystem. If you need to work directly with the VM or inspect implementation details, the confirmed repository is:

Step 6: Start with the smallest test matrix

Once you have syntax verified locally, your first tests should be behavioral, not exhaustive.

For the voucher contract, test at least:

  1. authorized issuer can issue;
  2. unauthorized issuer cannot issue;
  3. owner can redeem;
  4. non-owner cannot redeem;
  5. same voucher cannot redeem twice;
  6. redeemed mapping changes as expected.

If the local toolchain supports property-style or fuzz-style testing, use it later. For the first pass, deterministic scenario tests are enough.


A practical development workflow using verified pieces of the Aleo stack

Even though the Leo docs in the primer are unavailable, you can still set up a disciplined workflow around the parts we can verify.

Use snarkVM as your low-level anchor

The primer confirms that snarkVM is the VM and proving library stack, and that it can be used as a Rust dependency.

Documented dependency form:

[dependencies]
snarkvm = "major.minor.patch"

Do not hardcode a version from a random blog post. Pick the published version appropriate for your environment and confirm compatibility with your Leo/compiler setup.

Build from source when you need implementation clarity

The verified README documents:

git clone --branch staging --single-branch https://github.com/ProvableHQ/snarkVM.git
cd snarkVM
cargo build --release

That does not replace Leo docs, but it does give you an authoritative codebase when you need to inspect current implementation details, benchmarks, or VM-side behavior.

One practical use of this approach is version triage:

Keep your contract design document next to your code

This matters more in ZK than in ordinary app code.

Before writing the first transition, write a short design document with:

For the voucher example, the design doc might be one page. That page will save you more time than a copied code sample of uncertain version.

Treat proving costs as a real product constraint

Aleo programs are not just logic; they are logic that must be proved. So when you move from concept to implementation:

Because the primer does not give benchmark commands or constraint inspection APIs, I will not invent them here. But the engineering principle is clear: a contract that is elegant on paper but too expensive to prove is not production-ready.

Decide early what must be on-chain state

Developers often overuse mappings in their first privacy-preserving contract because mappings feel familiar. In Aleo, ask instead:

For many applications, the best Aleo design is:

That is where Aleo’s model is strongest.


Caveats

  1. No Leo syntax is presented as authoritative here.
    The primer’s Leo syntax and language URLs were unavailable at fetch time, so you should verify against your local installation/compiler version for all concrete declarations, transition signatures, storage syntax, and CLI commands.

  2. “Contract” is used informally.
    In Aleo/Leo contexts, the exact terminology in current docs may emphasize “programs” and “transitions.” Verify the current nomenclature in your toolchain and docs.

  3. Mappings, records, and transitions are explained at the concept level.
    The design guidance here is robust, but implementation details such as ownership encoding, visibility modifiers, or return semantics may differ by compiler version.

  4. Privacy is application-specific.
    Using records does not automatically guarantee that your application leaks nothing meaningful. Identifier choice, mapping keys, returned outputs, and transition structure can all affect linkability.

  5. Performance claims are intentionally omitted.
    The primer does not include verified benchmarking workflows or current proof-cost guidance, so you should measure with your actual local stack.

  6. Network and tooling compatibility must be checked locally.
    If you are targeting a specific Aleo network environment, confirm compatibility among your Leo compiler, snarkVM version, and deployment target before building product assumptions on top of examples from any third-party source.


See also

Verified URLs from the provided primer:

Primer URLs that were fetched but unavailable at the time:

If you are implementing this tutorial for real, the next correct step is simple: open your local Leo compiler/docs, verify the exact syntax for record, mapping, and transition declarations, and then implement the voucher design above with the five invariants explicitly tested. That will teach you more about whether Aleo fits your product than any copy-paste sample of uncertain version.


Where to go next

Thanks for reading this far. If “Your first Aleo program” connected with where you are, three concrete next steps:

Learn more in Aleo

The full Midnight ZK Cookbook index has 17 tutorials across Midnight, Aleo, Aztec, Noir, and risc0 plus 4 Chinese translations. Adjacent tutorials are listed by ecosystem on that page.

Find paid work in Aleo

Bounty Radar tracks open ZK bounties across Algora, GitHub labels, Drips Wave, Code4rena, and Bountycaster. Browse the Aleo sub-feed; JSON at /aleo.json. The free tier is poll-based; the $19/mo Hobbyist tier pushes one filter to your Telegram in real time.

Audit your own ZK pipeline

zk-pipeline-doctor is the free MIT-licensed CLI that scores any ZK project on tests, CI, docs, security, reproducibility, and language toolchain (supports Compact, Leo, Noir, Cairo, and 7 Rust zkVMs). Drop it into a GitHub Action with zk-doctor-action for diff-aware PR comments. The $15/mo Pro tier adds four cross-ecosystem deep detectors (circuit complexity, proving-system pitfalls, verifier soundness, multi-file consistency).


Drafted with AI assistance and reviewed by the author before publishing. See DISCLOSURE for the full process.

If this saved you time

Three ways to support this work, pick whichever matches your situation:

$15 · One-time
All 17 tutorials as one Markdown + companion code repos. Offline-readable.
Get the Bundle →
$19 / month
Real-time bounty alerts pushed to your Telegram, filtered by ecosystem.
Try Radar →
$99 · One-time
Pre-flight audit of your ZK repo. See sample.
Order Audit →

Free alternative: Sponsor on GitHub · Star the repo · Share with one ZK developer who'd benefit

Related projects