Beginner-friendly walkthrough for developers getting started with Midnight
If you're exploring Midnight development for the first time, shielded contracts can feel intimidating. Privacy-preserving logic is powerful, but it also adds complexity.
That’s why unshielded tokens are a good starting point.
In this tutorial, we’ll build a simple unshielded token dApp using Midnight, React, and Compact. The goal is to understand the full flow from contract structure to frontend interaction.
By the end, you’ll understand:
How an unshielded token flow works on Midnight
How to structure a Compact contract
How frontend interaction can be wired using React
Wallet connection basics
Minting, sending, and receiving token flow
When unshielded tokens make sense compared to shielded tokens
This tutorial is written for developers and newcomers who want a practical entry point into Midnight.
Why Start With Unshielded Tokens?
Midnight supports privacy-preserving applications, but not every use case needs maximum privacy from day one.
Unshielded tokens are useful when:
You want a simpler developer experience
You’re learning Midnight fundamentals
You need transparent balances and transfers
You want easier debugging during development
Since balances and transfers are visible, they’re easier to test and reason about.
Shielded tokens are better when privacy is the priority, but for learning and experimentation, unshielded tokens provide a much smoother starting point.
What We’re Building
We’ll create a small unshielded token dApp with:
Wallet connection
Mint functionality
Send functionality
Receive functionality
Balance display
React frontend UI
Compact contract artifacts
The frontend is built using React + Vite, while the contract side uses Compact.
The goal is not to build a production token system. Instead, we want a clean learning example that shows the full flow end-to-end.
Project Structure
The repository is organized like this:
midnight-unshielded-token-dapp/
│
├── contracts/
│ ├── unshielded-token.compact
│ └── managed/unshielded-token/
│
├── frontend/
│ ├── src/
│ └── package.json
│
├── scripts/
│ ├── local-api.mjs
│ ├── doctor.mjs
│ └── check-artifacts.mjs
│
├── tutorial.md
├── package.json
└── README.md
The project includes both the contract side and the frontend interface.
Prerequisites
Before starting, make sure you have:
macOS / Windows
Installed tools:
Node.js 20+
npm
Chrome or Brave browser
Midnight Lace Wallet
Docker Desktop (optional)
Check installation:

You should see installed versions.
**
Step 1: Clone the Repository
**
Clone the project locally.
git clone https://github.com/MayankSinghKholiya/midnight-unshielded-token-dapp.git
cd midnight-unshielded-token-dapp
Install dependencies:
npm install
npm run setup
Run environment checks:
npm run doctor
npm run check:artifacts
These commands help verify that the environment and generated artifacts are available.
Building an Unshielded Token dApp on Midnight with React and Compact
Beginner-friendly walkthrough for developers getting started with Midnight
If you're exploring Midnight development for the first time, shielded contracts can feel intimidating. Privacy-preserving logic is powerful, but it also adds complexity.
That’s why unshielded tokens are a good starting point.
In this tutorial, we’ll build a simple unshielded token dApp using Midnight, React, and Compact. The goal is to understand the full flow from contract structure to frontend interaction.
By the end, you’ll understand:
How an unshielded token flow works on Midnight
How to structure a Compact contract
How frontend interaction can be wired using React
Wallet connection basics
Minting, sending, and receiving token flow
When unshielded tokens make sense compared to shielded tokens
This tutorial is written for developers and newcomers who want a practical entry point into Midnight.
Why Start With Unshielded Tokens?
Midnight supports privacy-preserving applications, but not every use case needs maximum privacy from day one.
Unshielded tokens are useful when:
You want a simpler developer experience
You’re learning Midnight fundamentals
You need transparent balances and transfers
You want easier debugging during development
Since balances and transfers are visible, they’re easier to test and reason about.
Shielded tokens are better when privacy is the priority, but for learning and experimentation, unshielded tokens provide a much smoother starting point.
What We’re Building
We’ll create a small unshielded token dApp with:
Wallet connection
Mint functionality
Send functionality
Receive functionality
Balance display
React frontend UI
Compact contract artifacts
The frontend is built using React + Vite, while the contract side uses Compact.
The goal is not to build a production token system. Instead, we want a clean learning example that shows the full flow end-to-end.
Project Structure
The repository is organized like this:
midnight-unshielded-token-dapp/
│
├── contracts/
│ ├── unshielded-token.compact
│ └── managed/unshielded-token/
│
├── frontend/
│ ├── src/
│ └── package.json
│
├── scripts/
│ ├── local-api.mjs
│ ├── doctor.mjs
│ └── check-artifacts.mjs
│
├── tutorial.md
├── package.json
└── README.md
The project includes both the contract side and the frontend interface.
Prerequisites
Before starting, make sure you have:
macOS / Windows
Installed tools:
Node.js 20+
npm
Chrome or Brave browser
Midnight Lace Wallet
Docker Desktop (optional)
Check installation:
node -v
npm -v
You should see installed versions.
Step 1: Clone the Repository
Clone the project locally.
git clone https://github.com/MayankSinghKholiya/midnight-unshielded-token-dapp.git
cd midnight-unshielded-token-dapp
Install dependencies:
npm install
npm run setup
Run environment checks:
npm run doctor
npm run check:artifacts
These commands help verify that the environment and generated artifacts are available.
Step 2: Understanding the Compact Contract
Compact is Midnight’s contract language.
In this project, the contract focuses on unshielded token operations.
At a high level, the contract supports:
*Minting
*
Minting creates new tokens.
The token supply increases and tokens are assigned to an account.
This is useful for:
Initial token distribution
Testing balances
Simulating token issuance during development
*Sending Tokens
*
The transfer flow allows tokens to move between addresses.
This helps demonstrate how token interactions can be surfaced in a frontend.
Receiving Tokens
Receiving updates the user state and balance display after a transfer.
Even in a beginner project, seeing the complete transfer cycle makes the application easier to understand.
Compiling the Contract
To compile Compact code:npm run compile:contract
Or directly:compact compile contracts/unshielded-token.compact contracts/managed/unshielded-token
If compilation succeeds, generated artifacts will appear under:contracts/managed/unshielded-token/
This step matters because Midnight bounty submissions require compilable Compact code.
Step 3: Running the Local API
To simplify frontend testing, the project includes a local API adapter.
Start it using:npm run api:dev
This launches:http://localhost:4000/api
The API exposes endpoints used by the UI.
Examples include:GET /api/state
POST /api/mint
POST /api/send
POST /api/receive
This setup makes it easier to understand the interaction flow before moving to more advanced deployment environments.
Step 4: Running the React Frontend
Open a second terminal:cd frontend
npm install
npm run dev
Once Vite starts, open:http://localhost:5173

You should see the token dashboard UI.
The frontend provides:
Wallet interaction
Token action forms
Balance display
Status updates
This gives a complete beginner-friendly experience for understanding Midnight token operations.
Step 5: Wallet Connection
A dApp becomes much easier to understand once a wallet is involved.
The frontend checks for Midnight wallet availability and allows users to connect.
Why this matters:
Without wallet interaction, token operations feel disconnected from real user flows.
With wallet integration, the dApp starts to resemble how an actual Midnight application behaves.
In this project, wallet interaction is intentionally kept simple so newcomers can understand the basics first.
Step 6: Minting Tokens
Minting is usually the first action developers test.
The mint flow allows new tokens to be created and assigned.
In the UI:
Enter an amount
Click mint
Watch the balance update
This immediately gives feedback that the token logic is functioning.
For development and demos, minting is useful because it quickly creates test balances without external setup.
Step 7: Sending Tokens
After minting, the next step is transferring tokens.
The send flow demonstrates:
Address input
Amount input
Transaction submission
Balance updates
This makes the dApp feel interactive instead of static.
In a real-world application, this is where validation, permissions, and additional checks would usually be added.
For learning purposes, keeping the flow simple helps developers focus on understanding Midnight fundamentals.
Step 8: Receiving Tokens
Receiving tokens completes the loop.
Once tokens are transferred, balances should update correctly.
This helps demonstrate state changes inside the application.
A beginner-friendly project should always try to show the full flow:
Mint → Send → Receive → Balance Update
That complete cycle helps new developers understand how all pieces fit together.
Step 9: Frontend Build
To verify the frontend builds successfully:npm run frontend:build
OR
cd frontend
npm run build
You should see a successful build output.
This is important because working code and successful builds are required for Midnight technical submissions.
Unshielded vs Shielded Tokens
A common beginner question is:
When should I use unshielded tokens instead of shielded ones?
**Use Unshielded Tokens When
**You’re learning Midnight
You need easier debugging
Transparent transfers are acceptable
You want simpler frontend integration
**Use Shielded Tokens When
**Privacy matters
Transaction visibility should be hidden
Balances need protection
Sensitive financial logic is involved
There’s no single correct answer.
It depends on the application.
For example:
A public loyalty point system might work perfectly with unshielded tokens.
A financial privacy application would likely benefit from shielded transactions.
For newcomers, starting unshielded makes learning significantly easier.
Challenges Faced During Development
One thing worth mentioning is that environment setup can sometimes be the hardest part of Midnight development.
Wallet detection, Docker services, dependency versions, frontend configuration, and SDK compatibility may require patience during setup.
If something doesn’t work immediately, don’t assume you’re doing everything wrong.
Usually, checking:node -v
npm run doctor
npm run check:artifacts
helps identify missing dependencies or environment issues.
Final Thoughts
Midnight development can feel overwhelming at first, especially if privacy-preserving systems are new to you.
Starting with an unshielded token dApp makes the learning process much easier.
You still get to understand:
Contracts
Frontend interaction
Wallet integration
Token flows
State updates
without immediately jumping into more advanced privacy mechanics.
Once you’re comfortable with unshielded flows, moving into shielded applications becomes much more approachable.
If you're just getting started with Midnight, this is a practical place to begin.
Repository
GitHub Repository:
https://github.com/MayankSinghKholiya/midnight-unshielded-token-dapp
If you want to try the project yourself, clone the repository, run the setup commands, and experiment with the token flow locally.



Top comments (0)