Skills genlayer-dev-claw-skill
Build GenLayer Intelligent Contracts - Python smart contracts with LLM calls and web access. Use for writing/deploying contracts, SDK reference, CLI commands, equivalence principles, storage types. Triggers: write intelligent contract, genlayer contract, genvm, gl.Contract, deploy genlayer, genlayer CLI, genlayer SDK, DynArray, TreeMap, gl.nondet, gl.eq_principle, prompt_comparative, strict_eq, genlayer deploy, genlayer up. (For explaining GenLayer concepts, use genlayer-claw-skill instead.)
git clone https://github.com/openclaw/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/acastellana/genlayer-dev" ~/.claude/skills/clawdbot-skills-genlayer-dev-claw-skill && rm -rf "$T"
skills/acastellana/genlayer-dev/SKILL.mdGenLayer Intelligent Contracts
GenLayer enables Intelligent Contracts - Python smart contracts that can call LLMs, fetch web data, and handle non-deterministic operations while maintaining blockchain consensus.
Quick Start
Minimal Contract
# v0.1.0 # { "Depends": "py-genlayer:latest" } from genlayer import * class MyContract(gl.Contract): value: str def __init__(self, initial: str): self.value = initial @gl.public.view def get_value(self) -> str: return self.value @gl.public.write def set_value(self, new_value: str) -> None: self.value = new_value
Contract with LLM
# v0.1.0 # { "Depends": "py-genlayer:latest" } from genlayer import * import json class AIContract(gl.Contract): result: str def __init__(self): self.result = "" @gl.public.write def analyze(self, text: str) -> None: prompt = f"Analyze this text and respond with JSON: {text}" def get_analysis(): return gl.nondet.exec_prompt(prompt) # All validators must get the same result self.result = gl.eq_principle.strict_eq(get_analysis) @gl.public.view def get_result(self) -> str: return self.result
Contract with Web Access
# v0.1.0 # { "Depends": "py-genlayer:latest" } from genlayer import * class WebContract(gl.Contract): content: str def __init__(self): self.content = "" @gl.public.write def fetch(self, url: str) -> None: url_copy = url # Capture for closure def get_page(): return gl.nondet.web.render(url_copy, mode="text") self.content = gl.eq_principle.strict_eq(get_page) @gl.public.view def get_content(self) -> str: return self.content
Core Concepts
Contract Structure
- Version header:
(required)# v0.1.0 - Dependencies:
# { "Depends": "py-genlayer:latest" } - Import:
from genlayer import * - Class: Extend
(only ONE per file)gl.Contract - State: Class-level typed attributes
- Constructor:
(not public)__init__ - Methods: Decorated with
or@gl.public.view@gl.public.write
Method Decorators
| Decorator | Purpose | Can Modify State |
|---|---|---|
| Read-only queries | No |
| State mutations | Yes |
| Receive value + mutate | Yes |
Storage Types
Replace standard Python types with GenVM storage-compatible types:
| Python Type | GenVM Type | Usage |
|---|---|---|
| , , , , , etc. | Sized integers |
(unbounded) | | Arbitrary precision (avoid) |
| | Dynamic arrays |
| | Ordered maps |
| | Strings (unchanged) |
| | Booleans (unchanged) |
⚠️
is NOT supported! Always use sized integers.int
Address Type
# Creating addresses addr = Address("0x03FB09251eC05ee9Ca36c98644070B89111D4b3F") # Get sender sender = gl.message.sender_address # Conversions hex_str = addr.as_hex # "0x03FB..." bytes_val = addr.as_bytes # bytes
Custom Data Types
from dataclasses import dataclass @allow_storage @dataclass class UserData: name: str balance: u256 active: bool class MyContract(gl.Contract): users: TreeMap[Address, UserData]
Non-Deterministic Operations
The Problem
LLMs and web fetches produce different results across validators. GenLayer solves this with the Equivalence Principle.
Equivalence Principles
1. Strict Equality (strict_eq
)
strict_eqAll validators must produce identical results.
def get_data(): return gl.nondet.web.render(url, mode="text") result = gl.eq_principle.strict_eq(get_data)
Best for: Factual data, boolean results, exact matches.
2. Prompt Comparative (prompt_comparative
)
prompt_comparativeLLM compares leader's result against validators' results using criteria.
def get_analysis(): return gl.nondet.exec_prompt(prompt) result = gl.eq_principle.prompt_comparative( get_analysis, "The sentiment classification must match" )
Best for: LLM tasks where semantic equivalence matters.
3. Prompt Non-Comparative (prompt_non_comparative
)
prompt_non_comparativeValidators verify the leader's result meets criteria (don't re-execute).
result = gl.eq_principle.prompt_non_comparative( lambda: input_data, # What to process task="Summarize the key points", criteria="Summary must be under 100 words and factually accurate" )
Best for: Expensive operations, subjective tasks.
4. Custom Leader/Validator Pattern
result = gl.vm.run_nondet( leader=lambda: expensive_computation(), validator=lambda leader_result: verify(leader_result) )
Non-Deterministic Functions
| Function | Purpose |
|---|---|
| Execute LLM prompt |
| Fetch web page ( or ) |
⚠️ Rules:
- Must be called inside equivalence principle functions
- Cannot access storage directly
- Copy storage data to memory first with
gl.storage.copy_to_memory()
Contract Interactions
Call Other Contracts
# Dynamic typing other = gl.get_contract_at(Address("0x...")) result = other.view().some_method() # Static typing (better IDE support) @gl.contract_interface class TokenInterface: class View: def balance_of(self, owner: Address) -> u256: ... class Write: def transfer(self, to: Address, amount: u256) -> bool: ... token = TokenInterface(Address("0x...")) balance = token.view().balance_of(my_address)
Emit Messages (Async Calls)
other = gl.get_contract_at(addr) other.emit(on='accepted').update_status("active") other.emit(on='finalized').confirm_transaction()
Deploy Contracts
child_addr = gl.deploy_contract(code=contract_code, salt=u256(1))
EVM Interop
@gl.evm.contract_interface class ERC20: class View: def balance_of(self, owner: Address) -> u256: ... class Write: def transfer(self, to: Address, amount: u256) -> bool: ... token = ERC20(evm_address) balance = token.view().balance_of(addr) token.emit().transfer(recipient, u256(100)) # Messages only on finality
CLI Commands
Setup
npm install -g genlayer genlayer init # Download components genlayer up # Start local network
Deployment
# Direct deploy genlayer deploy --contract my_contract.py # With constructor args genlayer deploy --contract my_contract.py --args "Hello" 42 # To testnet genlayer network set testnet-asimov genlayer deploy --contract my_contract.py
Interaction
# Read (view methods) genlayer call --address 0x... --function get_value # Write genlayer write --address 0x... --function set_value --args "new_value" # Get schema genlayer schema --address 0x... # Check transaction genlayer receipt --tx-hash 0x...
Networks
genlayer network # Show current genlayer network list # Available networks genlayer network set localnet # Local dev genlayer network set studionet # Hosted dev genlayer network set testnet-asimov # Testnet
Best Practices
Prompt Engineering
prompt = f""" Analyze this text and classify the sentiment. Text: {text} Respond using ONLY this JSON format: {{"sentiment": "positive" | "negative" | "neutral", "confidence": float}} Output ONLY valid JSON, no other text. """
Security: Prompt Injection
- Restrict inputs: Minimize user-controlled text in prompts
- Restrict outputs: Define exact output formats
- Validate: Check parsed results match expected schema
- Simplify logic: Clear contract flow reduces attack surface
Error Handling
from genlayer import UserError @gl.public.write def safe_operation(self, value: int) -> None: if value <= 0: raise UserError("Value must be positive") # ... proceed
Memory Management
# Copy storage to memory for non-det blocks data_copy = gl.storage.copy_to_memory(self.some_data) def process(): return gl.nondet.exec_prompt(f"Process: {data_copy}") result = gl.eq_principle.strict_eq(process)
Common Patterns
Token with AI Transfer Validation
See
references/examples.md → LLM ERC20
Prediction Market
See
references/examples.md → Football Prediction Market
Vector Search / Embeddings
See
references/examples.md → Log Indexer
Debugging
- GenLayer Studio: Use
for local testinggenlayer up - Logs: Filter by transaction hash, debug level
- Print statements:
works in contracts (debug only)print()
Reference Files
- Complete SDK API referencereferences/sdk-api.md
- Consensus patterns in depthreferences/equivalence-principles.md
- Full annotated contract examples (incl. production oracle)references/examples.md
- CLI, networks, deployment workflowreferences/deployment.md
- VM architecture, storage, ABI detailsreferences/genvm-internals.md
Links
- Docs: https://docs.genlayer.com
- SDK: https://sdk.genlayer.com
- Studio: https://studio.genlayer.com
- GitHub: https://github.com/genlayerlabs