Hey everyone!
I’m proposing a standard for on-chain smart contract source code verification. This would enable anyone to verify that the bytecode running on Cardano matches the published source code - trustlessly and decentralized.
TL;DR - It’s Already Working
Live demo: http://uplc.link/
First verification on Preview: Cardano Explorer | Cexplorer.io
GitHub: GitHub - easy1staking-com/uplc-link: Like etherscan but for cardano
There’s already a working proof of concept for Aiken contracts and I’m now looking for community feedback before formalizing as a CIP.
Motivation
The Problem
Right now on Cardano:
- Smart contracts exist only as bytecode on-chain
- No way to verify the bytecode matches claimed source code
- Users must trust deployers about what code is actually running
- Block explorers can’t show verification status
- Each smart contract language (Aiken, Plutarch, Plutus, Scalus, Plu-ts, OpShin) has different compilation processes
Why Cardano Can Do Better Than Ethereum
Ethereum uses Etherscan for verification - a centralized service you have to trust. Cardano can do better:
- On-chain metadata = immutable verification records
- Transaction metadata = anyone can verify and submit
- Decentralized = no central authority required
- “Verify, don’t trust” = the blockchain way
Proposed Solution
Metadata Key: 1984 (temporarily)
The metadata key 1984 has been currently selected to be used as key, but could be changed in the future if a more meaningful number is found.
How It Works
For Contract Deployers:
- Deploy your contract
- Submit a transaction with metadata key
1984containing:- Compiler type (Aiken, Plutarch, etc.)
- GitHub org/repo
- Exact commit hash
- Compiler version
- Applied parameters (if any)
For Users/Verifiers:
- See a contract on-chain
- Query metadata key
1984 - Fetch source from GitHub
- Compile locally (or in browser with WASM)
- Compare hashes - verified!

For Block Explorers:
- Query verification database API
- Display verification badge
- Link to source code
Technical Specification
Metadata Structure
Due to Cardano’s 64-byte limit on metadata values, verification metadata is stored as an array of chunks:
{
"1984": [
"chunk_0", // First 64 bytes (hex)
"chunk_1", // Next 64 bytes (hex)
"chunk_2" // Remaining bytes
]
}
Reassembly: Concatenate chunks → hex-decode → deserialize as CBOR PlutusData
After Reassembly
verification_metadata = #6.121([
compiler_type, ; 0=Aiken, 1=Plutarch, 2=Plutus, 3=Scalus, 4=Plu-ts, 5=OpShin
source_url, ; Full repository URL (bytes, UTF-8)
commit_hash, ; Git commit hash (bytes, 20 or 32 bytes)
source_path, ; Path within repo (bytes, UTF-8, empty = root)
compiler_version, ; Version string (bytes, UTF-8, e.g., "v1.1.3")
script_parameters_map ; Map: script_hash => [parameters]
])
script_parameters_map = {
* script_hash => #6.121([* parameter])
}
script_hash = bytes .size 28 ; Blake2b-224 hash
parameter = bytes ; CBOR-encoded parameter value
Real Example
Transaction on Preview: Cardano Explorer | Cexplorer.io
Decoded metadata:
- Compiler: Aiken
- Source: GitHub - easy1staking-com/cardano-recurring-payment
- Commit:
35f1a0d51c8663782ab052f869d5c82b756e8615 - Version: v1.1.3
- Scripts: 2 validators with parameters
Raw CBOR:
a11907c0845840d8799f5065617379317374616b696e672d636f6d581963617264616e6f2d726563757272696e672d7061796d656e74...
Roadmap
Phase 1: Backend Verification
(Current)
- Status: Live at uplc.link and api.uplc.link
- Supports: Aiken (v1.1.3, v1.1.9 tested)
- Process: User inputs source location → backend compiles → compares hash
- Limitation: Results not persisted
Phase 2: Indexed Database + API
(Near-term)
- Indexer monitors blockchain for 1984 metadata
- Database stores verification records
- API for querying by script hash
- Block explorer integration
Phase 3: Browser-Based Verification
(Medium-term)
- WASM compiler bindings for client-side verification
- ~10 second verification in your browser
- No backend needed - pure trustless verification
- Applicable to: Aiken, and all languages which offer wasm bindings
- Not applicable to: Haskell-based compilers (Plutarch, Plutus)
Phase 4: Verification for contracts depending on Haskll
(Medium-Long-term)
- Haskell based contracts verification
API Example:
GET /api/verify/{script_hash}
Response: {
"verified": true,
"source_url": "https://github.com/org/repo/commit/abc123",
"compiler": "aiken",
"version": "1.1.3",
"verified_at": "2026-01-08T12:00:00Z"
}
Phase 4: Decentralized Ecosystem
(Future)
- NOT a consensus protocol
- Anyone can verify and submit 1984 metadata
- Multiple independent verifications encouraged
- Consumers (explorers, wallets) choose which to trust
- Open-source infrastructure = permissionless participation
Who Can Submit Verification Metadata?
Anyone. This is a key feature:
- Contract deployers can verify their own code
- Third-party auditors can independently verify
- Community members can verify public infrastructure
- Automated services can continuously verify
Multiple verification records for the same contract increase confidence.
Path to Active
This would become an Active CIP when:
Metadata format implemented (drafted)
Verification UI deployed (uplc.link)- At least 3 Cardano protocols register contracts using uplc-link metadata
- At least 1 block explorer integrates verification display
- At least 2 compilers supported (Aiken + one other)
- Documentation published for integrating additional compilers
Questions for the Community
-
Is the metadata structure clear and extensible? Can it handle edge cases you can think of?
-
Compiler enumeration - Is the fixed ID approach (0=Aiken, 1=Plutarch, etc.) okay? Or should it be more flexible?
-
Parameter encoding - Any concerns about how parameterized contracts are represented?
-
Multi-language support priority - Which compiler should we tackle after Aiken? Plutarch? Plu-ts? OpShin?
-
Block explorer interest - Any block explorer devs here interested in integrating this?
Implementation Details
Current tech stack:
- Java (cardano-client-lib) for metadata encoding/decoding
- Aiken compiler integration
- GitHub API for source fetching
- React frontend
Open source:
- UI: GitHub - easy1staking-com/uplc-link: Like etherscan but for cardano
- Looking for contributors!
Example code for encoding:
// Build metadata
var metadata = ConstrPlutusData.of(
compilerType.getCompileId(),
BytesPlutusData.of(sourceUrl),
BytesPlutusData.of(HexUtil.decodeHexString(commitHash)),
BytesPlutusData.of(optionalPath),
BytesPlutusData.of(compilerVersion),
scriptHashToParametersMap
);
// Serialize and chunk
String hex = HexUtil.encodeHexString(metadata.serialize());
List<String> chunks = splitIntoChunks(hex, 64);
// Submit as metadata
ListPlutusData chunkList = ListPlutusData.of(
chunks.stream()
.map(HexUtil::decodeHexString)
.map(BytesPlutusData::of)
.toList()
);
Why This Matters
Ethereum has Etherscan verification because it launched before anyone thought about decentralized alternatives. Cardano has the opportunity to do this the right way from the start - fully on-chain, permissionless, and trustless.
This isn’t just about technical correctness. It’s about:
- User safety - Know what code you’re interacting with
- Developer credibility - Prove your code is what you claim
- Ecosystem transparency - Build trust through verification
- Auditor efficiency - Direct link from on-chain to source
Call to Action
Feedback needed:
- Technical concerns with the metadata structure?
- Suggestions for improvement?
- Interest in contributing? (especially for other compilers)
- Block explorer devs - want to integrate?
Try it yourself:
- Visit http://uplc.link/
- Verify an Aiken contract
- Let me know what breaks or could be better
Next steps:
- Incorporate feedback from this discussion
- Write formal CIP
- Submit to GitHub
- Build out multi-compiler support
Thanks for reading! Looking forward to your thoughts.
EDIT 1: In order to cater for multiple git based solutions (github, gitlab, codeberg etc), org+repo has been replaced by source_url which should contain the full repository url, examples:
- “https://github.com/org/repo”
- “https://gitlab.com/group/subgroup/project”
- “https://codeberg.org/user/repo”
- “https://git.company.com/team/project”
EDIT 2: bought uplc.link domain, and updated all-the-links
