This is Part 1 of a 3-part tutorial series where we build GenBets -- a peer-to-peer betting dApp on GenLayer where friends bet on subjective outcomes and AI validators settle the result.
The Bet You Can't Settle on a Blockchain
Picture this: you and a friend are arguing about whether the latest Marvel movie is actually good. Not just box-office numbers -- you're debating whether it was well-received. Critics loved it, audiences were split, and Reddit is a warzone of hot takes. Your friend says it flopped creatively. You say it landed. So you make a bet.
Now here's the question nobody thinks to ask: who decides who wins? You could ask a mutual friend, but they might be biased. You could check Rotten Tomatoes, but what score counts as "well-received"? 85%? 70%? And what about audience scores versus critic scores? The whole thing is... subjective.
What if, instead of trusting a single person's judgment, the blockchain itself could read reviews, analyze sentiment, and reason about whether the movie was genuinely well-received -- and what if multiple independent AI models had to agree before anyone won? That is not science fiction. That is what GenLayer does, and by the end of this three-part series, you will have built exactly that.
The Problem: Smart Contracts Hit a Wall
If you have never touched blockchain before, here is the thirty-second version. A blockchain is a shared ledger that nobody owns but everyone can verify. A smart contract is a program that lives on that ledger -- it runs automatically, it cannot be tampered with, and it does exactly what its code says. Think of it as a vending machine: you put in the right inputs, you get the guaranteed output. No middleman needed.
That vending machine analogy, though, reveals the limitation. Traditional smart contracts are deterministic -- given the same input, they always produce the same output. They can add numbers, move tokens between accounts, and enforce rules like "only release payment after both parties sign." What they absolutely cannot do is think. They cannot read a news article and form an opinion. They cannot browse the web. They cannot interpret nuance.
So what happens when a smart contract needs real-world information? The blockchain world solved this with oracles -- services like Chainlink that feed external data into contracts. Need the current price of ETH? An oracle can provide that. Need last night's football scores? An oracle can deliver those too. Oracles are excellent at providing objective, verifiable facts: numbers, timestamps, binary outcomes.
But go back to our movie bet. No oracle can tell you whether a movie was "well-received." That requires reading multiple sources, weighing different perspectives, and making a judgment call. The same gap appears everywhere in real life: Did a startup's product launch "succeed"? Was a political debate performance "strong"? Did a restaurant "deserve" its Michelin star? These are the kinds of questions humans bet on, argue about, and make agreements around every single day -- and traditional smart contracts simply cannot handle them. There is a gap between what smart contracts can do and what real-world agreements actually need.
Enter GenLayer: The First AI-Native Blockchain
GenLayer closes that gap. It is a blockchain built from the ground up to integrate large language models (LLMs) into the contract execution layer itself. Contracts on GenLayer are not just deterministic code -- they are programs that can reason, browse the internet, and make nuanced judgments, all while maintaining the trustless guarantees that make blockchain valuable in the first place.
Let's break down the three pillars that make this work.
Intelligent Contracts: Smart Contracts That Think
On GenLayer, smart contracts are called Intelligent Contracts, and they are written in Python. If you are wondering why Python and not Solidity (the language most blockchains use), the answer is straightforward: Python is the lingua franca of AI and machine learning. When your contracts need to compose prompts, parse LLM outputs, and process web data, Python is the natural choice.
An Intelligent Contract looks like a regular Python class, but it has access to special functions that no traditional blockchain offers:
-
gl.nondet.exec_prompt()-- Sends a prompt to a large language model and gets back a response. Your contract can literally ask an AI a question and use the answer in its logic. -
gl.nondet.web.render()-- Fetches and renders a live web page, returning its content. Your contract can read news articles, check review aggregators, or pull data from any public URL.
These are called non-deterministic operations because, unlike adding two numbers, they might return slightly different results each time. Different LLMs might phrase the same answer differently. A web page might update between requests. GenLayer has a specific mechanism for handling this, which brings us to the next pillar.
Optimistic Democracy: How Validators Agree
If a contract calls an LLM, and different validators are connected to different LLMs (GPT-4, Claude, Gemini, etc.), how do they agree on a result? GenLayer uses a consensus mechanism called Optimistic Democracy. Here is how it works:
Transaction Submitted
|
v
+---------------------+
| Leader Validator | <-- Randomly selected
| (runs the contract |
| and proposes an |
| output) |
+---------------------+
|
v
+-------------------------------+
| Validator Set |
| [V1] [V2] [V3] [V4] | <-- Each connected to
| | | | | | a different LLM
| v v v v |
| verify verify verify verify|
| | | | | |
| v v v v |
| vote vote vote vote |
+-------------------------------+
|
v
Majority Agrees?
/ \
Yes No
| |
v v
Transaction Transaction
Accepted Rejected
|
v
+--- Appeal Window ---+
| Anyone can challenge |
| by posting a bond. |
| Validator set doubles|
| and re-votes. |
+----------------------+
A randomly selected subset of validators processes each transaction. One validator is chosen as the leader -- it runs the contract and proposes an output. The remaining validators then independently run the same contract and vote on whether the leader's output is acceptable. If a majority agrees, the transaction goes through.
But there is an important safety net: the appeal window. After a transaction is accepted, anyone who disagrees with the result can challenge it by posting a bond (putting tokens at stake). When a challenge is filed, the validator set doubles in size and the transaction is re-processed. This means bad results can be overturned, but frivolous challenges are discouraged because the challenger loses their bond if the original result holds. It is democracy with skin in the game.
The Equivalence Principle: Agreeing on "Close Enough"
Here is the subtle problem: if you ask GPT-4 and Claude the same question, they will give you correct but differently worded answers. "The movie was well-received" and "Critics and audiences responded positively to the film" mean the same thing, but they are different strings. A naive equality check would reject the transaction every time.
GenLayer solves this with the Equivalence Principle -- a mechanism that defines what "agreement" means for non-deterministic outputs. There are three variants, and choosing the right one is a key design decision when writing Intelligent Contracts:
1. Strict Equality -- gl.eq_principle.strict_eq()
The simplest form. The leader's output must exactly match what each validator produces. This works when you design the non-deterministic function to produce a single, deterministic output -- for example, returning a single word like "creator" or "opponent" rather than free-form text. If the LLM's answer is normalized to one of a small set of possible values, every validator will produce the same string, and strict equality passes cleanly.
# Example: strict equality for normalized single-word output
winner = gl.eq_principle.strict_eq(nondet)
# Every validator must return exactly the same string
2. Comparative -- gl.eq_principle.prompt_comparative()
Both the leader and each validator perform the same task independently. Then an LLM compares their outputs to see if they are substantively equivalent. This works well for quantitative or structured outputs where you expect the same conclusion but possibly different wording.
# Example: comparative equivalence
with gl.eq_principle.prompt_comparative(
"Are these two summaries making the same factual claims?"
):
result = gl.nondet.exec_prompt("Summarize this data...")
# Validators do the same work, then compare
3. Non-Comparative -- gl.eq_principle.prompt_non_comparative()
Validators do not replicate the leader's work. Instead, they assess the leader's output against a set of criteria. Think of it like a teacher grading an essay: the teacher does not write their own essay first -- they just evaluate whether the submitted one meets the requirements. This is ideal for subjective, qualitative assessments.
# Example: non-comparative equivalence
result = gl.eq_principle.prompt_non_comparative(
my_function,
task="Summarize the sentiment of these reviews",
criteria="The summary should accurately reflect the overall tone"
)
Which does GenBets use? GenBets uses strict_eq with a clever design: instead of asking the LLM to return complex JSON or free-form text, we ask it to return exactly one word -- either "creator" or "opponent." The code then normalizes the response with .strip().lower() and checks whether "creator" appears in the result. This means every validator, regardless of which LLM it runs, will produce the same single-word output: either "creator" or "opponent". Since the output is a simple, deterministic string, strict_eq passes reliably. We will see this pattern in detail in Part 2.
Meet GenBets: What We Are Building
Across this three-part series, we are building GenBets -- a peer-to-peer betting platform for subjective outcomes. No bookmakers, no centralized judges, no oracles feeding in predetermined data points. Just two people, a bet, and AI-powered validators that settle it.
Here is how it works:
+------------------+ +-------------------+ +--------------------+
| 1. CREATE BET | | 2. ACCEPT BET | | 3. RESOLVE BET |
| | | | | |
| Creator defines: | ----> | Opponent accepts | ----> | Anyone triggers |
| - Description | | the bet | | resolution |
| - Resolution URL | | | | |
| - Criteria | | Bet status moves | | Contract fetches |
| - Opponent addr | | to "accepted" | | data from URL, |
| | | | | LLM evaluates |
| Names opponent | | | | against criteria |
+------------------+ +-------------------+ +--------------------+
|
v
+-------------------------+
| 4. VALIDATORS VERIFY |
| |
| Multiple validators |
| (different LLMs) |
| independently check |
| the result via |
| Optimistic Democracy |
+-------------------------+
|
v
+-------------------------+
| 5. RESULT RECORDED |
| |
| Winner ("creator" or |
| "opponent") is stored |
| on-chain. |
| |
+-------------------------+
For example, you might create a bet: "The new Dune movie will be well-received by critics", set the resolution URL to Rotten Tomatoes, define your criteria as "well-received means a critic score above 75% and generally positive consensus", and name your friend as the opponent. Your friend accepts the bet. After the movie releases, anyone triggers resolution. The contract fetches the Rotten Tomatoes page, an LLM evaluates the reviews against your criteria, validators verify the judgment, and the winner is recorded on-chain. All transparent, all trustless.
Setting Up Your Environment
Let's get your local development environment ready so you can hit the ground running in Part 2.
Prerequisites
You need two things installed on your machine:
- Node.js 18+ -- Download from nodejs.org if you do not have it. Verify with:
node --version
# Should output v18.x.x or higher
- A modern browser -- Chrome, Firefox, or Edge. You will use it to access GenLayer Studio.
Install the GenLayer CLI
The GenLayer CLI is a command-line tool that sets up and manages your local GenLayer development environment. Install it globally with npm:
npm install -g genlayer
Initialize Your Local Environment
Once installed, spin up a local GenLayer network with three validators:
genlayer init --numValidators 3 --reset-db
This command pulls the necessary Docker containers, configures three validator nodes (each connected to a different LLM), and sets up a local blockchain instance. It may take a few minutes on the first run.
Open GenLayer Studio
Once initialization completes, open your browser and navigate to:
http://localhost:8080/
Welcome to GenLayer Studio -- your development playground. Take a moment to familiarize yourself with the interface:
- Contract Editor (center panel) -- This is where you write your Intelligent Contracts in Python. It has syntax highlighting and is where we will spend most of our time in Part 2.
- Accounts Panel (sidebar) -- You will see several pre-funded test accounts. These come loaded with test tokens so you can deploy contracts and send transactions without any real money.
- Transaction History (bottom panel) -- Every transaction you submit shows up here, including its status, the validator votes, and the final result. This is invaluable for debugging.
We will use Studio's built-in web editor for Parts 1 and 2 of this series. In Part 3, when we build the frontend, we will switch to a local project repository with a proper development setup.
What's Next
In Part 2, we will write the GenBets Intelligent Contract in Python from scratch -- including the AI-powered resolution logic that reads live web data, prompts an LLM to evaluate subjective criteria, and lets validators reach consensus through the Equivalence Principle. That is where the real magic happens. See you there.
Top comments (0)