Smart Contracts That Can Browse the Internet
Imagine a smart contract that can check a sports score, verify a news headline, or read a product price — all on-chain, with consensus. Traditional smart contracts are blind to the outside world. They can only work with data that's explicitly fed to them through oracles or manual transactions.
GenLayer changes this. Its Intelligent Contracts can fetch live web pages and call LLMs directly, then reach agreement among validators on what the result means. This article walks you through how that works, starting from zero.
What Makes This Possible: Non-Deterministic Blocks
The core challenge is simple: if a contract fetches a web page, two validators might get slightly different results (ads change, timestamps shift, content updates). Traditional blockchains can't handle this — they require every node to produce the exact same output.
GenLayer solves this with non-deterministic blocks — special Python functions where web fetches and LLM calls are allowed. After each validator runs the block independently, GenLayer's consensus mechanism (the Equivalence Principle) determines whether the results are "close enough" to agree on.
Here's the mental model:
Deterministic code → same input, same output (like normal smart contracts)
Non-deterministic block → validators may get different raw results
Equivalence Principle → validators agree on whether results are equivalent
Your First Web-Reading Contract
Let's build a contract that checks whether a webpage contains a specific link. This is the simplest possible example of web connectivity:
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
from genlayer import *
class WebChecker(gl.Contract):
has_link: bool
def __init__(self, url: str, keyword: str):
target_url = url
target_keyword = keyword
def check_page():
web_data = gl.nondet.web.render(target_url, mode='html')
return target_keyword in web_data
self.has_link = gl.eq_principle.strict_eq(check_page)
@gl.public.view
def result(self) -> bool:
return self.has_link
Let's break down what's happening:
-
The version comment on line 1 pins the GenVM runtime version (like Solidity's
pragma) -
gl.nondet.web.render()fetches a live web page inside the non-deterministic block -
gl.eq_principle.strict_eq()tells validators to compare results with exact equality — if all validators getTrue, consensus passes
The Rules of Non-Deterministic Blocks
There are a few constraints that keep the system safe:
- No storage access — you cannot read or write contract state inside a non-deterministic block
- No side effects leak out — changes to Python globals inside the block don't persist
-
Web calls must happen inside an equivalence principle call — calling
gl.nondet.web.render()outside ofgl.eq_principle.*will throw an error - The block is a zero-argument function — it captures variables from the surrounding scope via closure
Think of it like a sandbox: the contract says "go look at the world and tell me what you found," then validators compare notes.
Choosing the Right Equivalence Method
GenLayer offers different ways for validators to agree:
| Method | Use When |
|---|---|
gl.eq_principle.strict_eq() |
Result is a simple value (bool, number) where exact match makes sense |
gl.eq_principle.prompt_comparative() |
Result is text/complex data where an LLM should judge equivalence |
For our web-checker example, strict_eq is perfect — we're returning a boolean. But if you were summarizing a news article, you'd use prompt_comparative so validators can agree that two slightly different summaries convey the same meaning.
A Practical Example: Price Threshold Monitor
Here's a slightly more useful contract — it checks whether a product page shows a price below a threshold:
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
from genlayer import *
class PriceMonitor(gl.Contract):
item_url: str
threshold: str
is_below_threshold: bool
def __init__(self, item_url: str, threshold: str):
self.item_url = item_url
self.threshold = threshold
self.is_below_threshold = False
@gl.public.write
def check_price(self):
url = self.item_url
limit = self.threshold
def fetch_and_compare():
page = gl.nondet.web.render(url, mode='text')
prompt = f"Extract the main product price from this page and tell me if it is below {limit}. Answer only YES or NO.
Page content:
{page}"
result = gl.nondet.llm.call(prompt)
return result.strip().upper() == "YES"
self.is_below_threshold = gl.eq_principle.strict_eq(fetch_and_compare)
@gl.public.view
def below_threshold(self) -> bool:
return self.is_below_threshold
This combines both web fetching and LLM reasoning inside a single non-deterministic block. The LLM extracts the price and makes the comparison, then validators agree on the boolean result.
Key Takeaways
- GenLayer contracts can read live web data — no external oracle infrastructure needed
- Non-deterministic blocks are sandboxed functions where web and LLM calls happen, isolated from contract storage
- The Equivalence Principle handles consensus — validators independently execute the block and agree on results
-
strict_eqworks for simple values, whileprompt_comparativehandles fuzzy text comparison - You write everything in Python — no new language to learn, just a few GenLayer-specific patterns
Next Steps
Ready to try this yourself? Head to GenLayer Studio — it's a zero-setup web IDE where you can write, deploy, and test Intelligent Contracts in your browser. No Docker, no local install needed.
For a full local development environment with testing and linting, check out the GenLayer Project Boilerplate and the official documentation.
Top comments (0)