How to Define Public View Methods in GenLayer Smart Contracts

Define public view methods in GenLayer by importing the SDK and applying the @gl.public.view decorator to Python functions that read contract state without modifying it.

GenLayer smart contracts are written in Python and deployed to a blockchain environment that requires explicit decorators to expose callable methods. The genlayer-project-boilerplate repository demonstrates how to implement read-only query functions that access persistent storage while maintaining the immutability guarantees required by the virtual machine.

Understanding Public View Methods in GenLayer

A public view method is a read-only entry point that queries contract state without triggering state transitions. Unlike write methods that modify storage and consume gas for computation, view methods are pure operations that return serialized data to callers without requiring transaction fees.

In the GenLayer SDK, these methods serve as the primary interface for frontend applications, external contracts, and off-chain scripts to inspect contract data. The GenLayer VM enforces purity at runtime—any attempt to modify state or invoke non-deterministic operations inside a view method results in an execution error.

The @gl.public.view Decorator Syntax

To declare a view method, apply the @gl.public.view decorator directly above the method definition. The decorator signals to the compiler and VM that the function should be exposed in the contract's ABI as a view function and allows read access to storage variables.

from genlayer import *

class ExampleContract(gl.Contract):
    data: TreeMap[str, u256]

    @gl.public.view
    def read_data(self, key: str) -> u256:
        """Read from storage and return a value."""
        return self.data.get(key, 0)

Key requirements for view methods:

  • Import requirement: Must import from genlayer import * to access the decorator and types
  • Return serialization: Return values must be JSON-serializable (dict, list, int, str, or bool)
  • Storage access: Can read from storage types like TreeMap, DynArray, and persistent class attributes
  • Purity enforcement: Cannot reassign storage variables or call gl.nondet.* functions

Basic View Method Implementation

The simplest view methods return primitive values stored in contract attributes. These methods provide transparency into contract state without exposing the raw storage structure.

from genlayer import *

class Counter(gl.Contract):
    value: u256

    def __init__(self):
        self.value = 0

    @gl.public.write
    def increment(self):
        self.value += 1

    @gl.public.view
    def get_value(self) -> u256:
        """Return the current counter value."""
        return self.value

In this example, get_value qualifies as a view method because it only reads self.value without modification. The method returns a u256 integer that the GenLayer VM automatically serializes for the caller.

Returning Complex Data Structures

When contracts store dataclasses or nested mappings, view methods must format data into serializable Python dictionaries. The GenLayer VM does not automatically serialize custom objects, so explicit conversion is required.

from genlayer import *
from dataclasses import dataclass

@allow_storage
@dataclass
class Profile:
    name: str
    age: u256

class UserDirectory(gl.Contract):
    profiles: TreeMap[Address, Profile]

    def __init__(self):
        self.profiles = TreeMap()

    @gl.public.view
    def get_profile(self, addr: str) -> dict:
        """Return profile data as a serializable dictionary."""
        p = self.profiles.get(Address(addr), None)
        if p is None:
            return {}
        return {"name": p.name, "age": int(p.age)}

This pattern ensures that complex storage types are converted to JSON-compatible structures before returning to the caller.

Querying Mappings with Address Keys

A common pattern in GenLayer contracts involves iterating over TreeMap structures that use Address types as keys. Since JSON object keys must be strings, view methods should convert Address objects to hex string representations using the .as_hex property.

@gl.public.view
def get_bets(self) -> dict:
    """Expose all bets with address hex strings as keys."""
    return {k.as_hex: v for k, v in self.bets.items()}

This approach converts non-serializable Address keys into hex strings while preserving the mapping structure for external consumers.

Real-World Example from FootballBets

The genlayer-project-boilerplate repository implements multiple view methods in contracts/football_bets.py (lines 109-119) that demonstrate production-ready patterns for state querying.

According to the source code, the FootballBets contract defines three public view methods:

  • get_bets – Returns the complete TreeMap of bets indexed by address
  • get_points – Returns the points mapping for all participants
  • get_player_points – Returns the point total for a specific address as an integer

These methods use the @gl.public.view decorator and return dictionaries or integers derived from the contract's TreeMap storage without modifying self.bets or self.points. The implementation at lines 109-119 shows the exact syntax for exposing contract state while maintaining read-only guarantees.


# From contracts/football_bets.py, lines 109-119

@gl.public.view
def get_bets(self) -> dict:
    return {k.as_hex: v for k, v in self.bets.items()}

@gl.public.view  
def get_points(self) -> dict:
    return {k.as_hex: v for k, v in self.points.items()}

@gl.public.view
def get_player_points(self, addr: str) -> u256:
    return self.points.get(Address(addr), 0)

State Access Rules and Restrictions

The GenLayer VM enforces strict purity constraints on view methods during execution. Understanding these boundaries prevents runtime errors when deploying contracts.

Allowed operations:

  • Reading from TreeMap, DynArray, and persistent class attributes
  • Constructing and returning dict, list, int, str, or bool values
  • Calling other view methods within the same contract

Prohibited operations:

  • Assigning values to storage variables (e.g., self.bets[addr] = value)
  • Invoking gl.nondet.* functions for non-deterministic outcomes
  • Calling write methods or external contracts that modify state
  • Performing I/O operations or accessing external APIs

Attempting any prohibited operation triggers a runtime validation error that reverts the view call.

Summary

  • Use @gl.public.view to mark Python methods as read-only entry points in GenLayer contracts from the genlayer-project-boilerplate repository.
  • Return JSON-serializable types (dict, list, int, str) when exposing complex storage structures like TreeMap or dataclasses.
  • Reference storage directly via self.attribute notation to read contract state without gas fees.
  • Avoid state mutations and gl.nondet.* calls inside view methods, as the VM enforces purity at runtime.
  • Convert Address keys to hex strings using .as_hex when returning mapping data to ensure JSON compatibility.

Frequently Asked Questions

What happens if I modify state inside a @gl.public.view method?

The GenLayer VM detects state modifications during execution and raises a runtime error that reverts the view call. View methods must remain pure—any assignment to storage variables like self.data[key] = value or calls to write methods will fail validation, preventing the method from completing successfully.

Can view methods call other methods within the same contract?

View methods can safely call other methods decorated with @gl.public.view, but cannot invoke methods marked with @gl.public.write or any function that performs state modifications. The purity constraint applies recursively—any operation invoked by a view method must also adhere to read-only restrictions.

How do I return nested Mapping data from a view method?

Iterate over the TreeMap or storage container and construct a Python dict with serializable keys and values. When using Address types as keys, convert them to hex strings using address.as_hex because JSON requires string keys. The FootballBets contract in contracts/football_bets.py demonstrates this pattern by returning {k.as_hex: v for k, v in self.bets.items()}.

Do view methods consume gas when called?

No, view methods do not consume gas because they do not modify blockchain state or require transaction processing. External callers can query these methods through the contract ABI without submitting a transaction, making them ideal for frontend applications that need to display contract data efficiently.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →