Your First Contract
While GenLayer contract is a pure Python program, few things must be presented in your file.
Magic 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 standard library
Then you should import genlayer standard library:
from genlayer import *
This will import all types to the global scope, and everything else under gl
namespace.
Finally, the contract
Contract is a Python class, with regular constructor and methods which allows you to use your favorite IDE for type checking and auto completion.
However, there are some catches:
- This class must be decorated with
@gl.contract
so that magic happens - All persistent data should be declared as class fields and annotated with types
- Note that not all types are supported, but there are rewriting rules:
list[T]
→DynArray[T]
dict[K, V]
→TreeMap[K, V]
int
type isn't supported on purpose. You most likely wish to use some fixed-size integer type, such asi32
oru256
. If this is not the case and you are sure that you need big integers, you can annotate your field withbigint
, which is just an alias for pythonint
- Only fully instantiated generic types can be used, so
TreeMap
is forbidden, whileTreeMap[str, u256]
is not
- Note that not all types are supported, but there are rewriting rules:
- All 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 annotated)
# { "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.