Build with GenLayer
Your First Contract

Your First Contract

While a GenLayer Intelligent Contract is a pure Python program, there are few things that must be present in your file.

Version Comment

First of all, you need to place a magic comment with the version of GenVM you wish to use on the first line of your file

# { "Depends": "py-genlayer:test" }

It is similar to Solidity's pragma solidity, and test after a colon is a version. When GenLayer releases, it will be changed to some exact hash of a version, which will be frozen forever.

Importing the Standard Library

After the version comment, you can import the GenLayer standard library:

from genlayer import *

This will import all necessary types into the global scope, and everything else under gl namespace.

The Contract Class

An Intelligent Contract is a regular Python class, with a regular constructor and methods, which allows you to use your favorite IDE for type checking and auto completion. However, there are some additional requirements to make a class an Intelligent Contract.

Decorators

The GenVM makes use of decorators to identify the contract class and its methods.

The contract class must be decorated with @gl.contract so that GenVM knows that it's an Intelligent Contract. There can be only one contract class in a file.

Furthermore, ll public methods must be decorated with either @gl.public.view for read-only methods or @gl.public.write for methods that modify storage. Constructor (__init__) must be private (not decorated)

Persistent data

The GenVM enables Intelligent Contracts to maintain persistent data. This data is stored on the blockchain and can be accessed and modified via transactions.

This is done by declaring fields in the contract class.

⚠️

All persistent fields must be declared in the class body and annotated with types.

🚫

Fields declared outside the class body by creating new instance variables (self.field = value) are not persistent and will be discarded after the contract execution.

Types

In your contracts, you can use any Python types, but for persisted fields, there are some restrictions:

  • list[T] needs to be replaced with DynArray[T]
  • dict[K, V] needs to be replaced with TreeMap[K, V]
  • int type isn't supported on purpose. You most likely wish to use some fixed-size integer type, such as i32 or u256. If this is not the case and you are sure that you need big integers, you can annotate your field with bigint, which is just an alias for python int
⚠️

Only fully instantiated generic types can be used, so TreeMap is forbidden, while TreeMap[str, u256] is not

Example

Here is a simple example of an Intelligent Contract that stores a name and allows changeing it:

# { "Depends": "py-genlayer:test" }
 
from genlayer import *
 
@gl.contract
class Hello:
    name: str
 
    def __init__(self, name: str):
        self.name = name
 
    @gl.public.view
    def run(self) -> str:
        return f'Hello, {self.name}'
 
    @gl.public.write
    def set_name(self, name: str):
        print(f'debug old name: {self.name}') # <- you can use prints for debugging
            # they will be included in the GenVM execution log
        self.name = name
👾

The GenLayer Studio automatically detects the constructor parameters from your code. When you run your contract in the Studio, it provides the UI for all parameters for both constructor and methods, making it easy to manage and modify these inputs.