CIP Idea - Smart Contract Source Code Verification Metadata

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

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:

  1. Deploy your contract
  2. Submit a transaction with metadata key 1984 containing:
    • Compiler type (Aiken, Plutarch, etc.)
    • GitHub org/repo
    • Exact commit hash
    • Compiler version
    • Applied parameters (if any)

For Users/Verifiers:

  1. See a contract on-chain
  2. Query metadata key 1984
  3. Fetch source from GitHub
  4. Compile locally (or in browser with WASM)
  5. Compare hashes - verified! :white_check_mark:

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:

Raw CBOR:

a11907c0845840d8799f5065617379317374616b696e672d636f6d581963617264616e6f2d726563757272696e672d7061796d656e74...

Roadmap

Phase 1: Backend Verification :white_check_mark: (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 :counterclockwise_arrows_button: (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 :counterclockwise_arrows_button: (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 :counterclockwise_arrows_button: (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 :thought_balloon: (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:

  1. :white_check_mark: Metadata format implemented (drafted)
  2. :white_check_mark: Verification UI deployed (uplc.link)
  3. At least 3 Cardano protocols register contracts using uplc-link metadata
  4. At least 1 block explorer integrates verification display
  5. At least 2 compilers supported (Aiken + one other)
  6. Documentation published for integrating additional compilers

Questions for the Community

  1. Is the metadata structure clear and extensible? Can it handle edge cases you can think of?

  2. Compiler enumeration - Is the fixed ID approach (0=Aiken, 1=Plutarch, etc.) okay? Or should it be more flexible?

  3. Parameter encoding - Any concerns about how parameterized contracts are represented?

  4. Multi-language support priority - Which compiler should we tackle after Aiken? Plutarch? Plu-ts? OpShin?

  5. 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:

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

:folded_hands: Feedback needed:

  • Technical concerns with the metadata structure?
  • Suggestions for improvement?
  • Interest in contributing? (especially for other compilers)
  • Block explorer devs - want to integrate?

:hammer: Try it yourself:

  • Visit http://uplc.link/
  • Verify an Aiken contract
  • Let me know what breaks or could be better

:memo: 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:

EDIT 2: bought uplc.link domain, and updated all-the-links

7 Likes

@nemo83 I’d be happy to see this CIP draft submitted when ready, and I think it’s a great help to involve the community first. Normally feedback about what goes into a design is posted and/or evolves after a CIP draft is published, but I believe the results can/will be better if potential implementors can specify how they’d like a system to work & features they’d like to see added.

I can imagine that your CIP would fulfill a similar goal to CIP-0088’s stated goal of providing a decentralised alternative to the Cardano Token Registry: CIP-0088 > Motivation

When you choose your preferred metadata key, it helps to include a CIP-0010 update in the repository PR that you submit. Therefore it would save time to choose that number beforehand, i.e. here in this forum thread… I think 1984 is fine & easy to remember from the familiar book, which also addresses “trust” and “centralization” issues. (The number is close to other used numbers, but that’ll always be the case for recent calendar years.)

That’s great to see so much material about your PoC / reference implementation as the starting point to your Path to Active. Your work seems already disposed for other parties besides your own working group to cooperate with the proposal readily & promote its acceptance as a “standard”.

You probably already know that the contents of that reference implementation don’t have to (and shouldn’t be) submitted with the CIP itself. Since some of the “roadmap” is also specific to a particular implementation timeline and therefore not to the proposal itself, the best home for that detail would be on your own GitHub repository rather than the CIP directory.

I hope to see developers with relevant experience respond to your Questions for the community and look forward to tagging representative devs after you’ve posted this as a CIP PR. :nerd_face:

2 Likes

I don’t like that it defaults to GitHub. There are many reasons to move off GitHub.

Can it be changed to allow any URL to any Git repository if hosted on GitHub, GitLab, Codeberg, own server, …?

2 Likes

Great point and thanks for listing a few alternatives, I guess I should refactor this to crate a Source union type of which Github would be one of. This will make the design extensible.

2 Likes

thanks for all the super useful feedback.

2 Likes

I would find just a URL (in one of the formats supported by git clone) more flexible. Wouldn’t even need any action to extend.

I thought about your suggestions and it makes a lot of sense, I’ve updated the original post and the api already.

This is the current result.

1 Like

Hello,

I just released https://uplc.link

Announcement and details: https://x.com/CryptoJoe101/status/2010366269904613450

2 Likes