Source code for genlayer.std.genvm_contracts

__all__ = (
	'ContractAt',
	'contract_interface',
	'deploy_contract',
	'TransactionDataKwArgs',
	'DeploymentTransactionDataKwArgs',
)

import typing
import json
import collections.abc

from genlayer.py.types import Address, Lazy
import genlayer.py.calldata as calldata
import genlayer.std._wasi as wasi


from ._internal import decode_sub_vm_result, lazy_from_fd


def _make_calldata_obj(method, args, kwargs):
	ret = {'method': method}
	if len(args) > 0:
		ret.update({'args': args})
	if len(kwargs) > 0:
		ret.update({'kwargs': kwargs})
	return ret


from ._internal.result_codes import StorageType


class GenVMCallKwArgs(typing.TypedDict):
	"""
	Built-in parameters of performing a GenVM call view method

	.. warning::
		parameters are subject to change!
	"""

	state: typing.NotRequired[StorageType]


class _ContractAtViewMethod:
	def __init__(self, addr: Address, name: str, data: GenVMCallKwArgs):
		self.addr = addr
		self.name = name
		data.setdefault('state', StorageType.DEFAULT)
		self.data = data

	def __call__(self, *args, **kwargs) -> typing.Any:
		return self.lazy(*args, **kwargs).get()

	def lazy(self, *args, **kwargs) -> Lazy[typing.Any]:
		obj = _make_calldata_obj(self.name, args, kwargs)
		cd = calldata.encode(obj)
		return lazy_from_fd(
			wasi.call_contract(self.addr.as_bytes, cd, json.dumps(self.data)),
			decode_sub_vm_result,
		)


[docs] class TransactionDataKwArgs(typing.TypedDict): """ Built-in parameters of all transaction messages that a contract can emit .. warning:: parameters are subject to change! """ pass
class _ContractAtEmitMethod: def __init__(self, addr: Address, name: str, data: TransactionDataKwArgs): self.addr = addr self.name = name self.data = data def __call__(self, *args, **kwargs) -> None: obj = _make_calldata_obj(self.name, args, kwargs) cd = calldata.encode(obj) wasi.post_message(self.addr.as_bytes, cd, json.dumps(self.data)) class GenVMContractProxy[TView, TSend](typing.Protocol): __slots__ = ('_view', '_send', 'address') address: Address """ Address to which this proxy points """ def __init__( self, address: Address, ): self.address = address def view(self) -> TView: ... def emit(self, **kwargs: typing.Unpack[TransactionDataKwArgs]) -> TSend: ...
[docs] class ContractAt(GenVMContractProxy): """ Provides a way to call view methods and send transactions to GenVM contracts """
[docs] def __init__(self, addr: Address): if not isinstance(addr, Address): raise Exception('address expected') self.addr = addr
[docs] def view(self): """ Namespace with all view methods """ return _ContractAtView(self.addr, {})
[docs] def emit(self, **data: typing.Unpack[TransactionDataKwArgs]): """ Namespace with write message """ return _ContractAtEmit(self.addr, data)
class _ContractAtView: def __init__(self, addr: Address, data): self.addr = addr self.data = data def __getattr__(self, name): return _ContractAtViewMethod(self.addr, name, self.data) class _ContractAtEmit: def __init__(self, addr: Address, data: TransactionDataKwArgs): self.addr = addr self.data = data def __getattr__(self, name): return _ContractAtEmitMethod(self.addr, name, self.data) class GenVMContractDeclaration[TView, TWrite](typing.Protocol): View: type[TView] """ Class that contains declarations for all view methods """ Write: type[TWrite] """ Class that contains declarations for all write methods .. note:: all return type annotations must be either empty or ``None`` """
[docs] def contract_interface[TView, TWrite]( _contr: GenVMContractDeclaration[TView, TWrite], ) -> typing.Callable[[Address], GenVMContractProxy[TView, TWrite]]: # editorconfig-checker-disable """ This decorator produces an "interface" for other GenVM contracts. It has no semantical value, but can be used for auto completion and type checks .. code-block:: python @gl.contract_interface class MyContract: class View: def view_meth(self, i: int) -> int: ... class Write: def write_meth(self, i: int) -> None: ... """ # editorconfig-checker-enable return ContractAt
from genlayer.py.types import u8, u256
[docs] class DeploymentTransactionDataKwArgs(TransactionDataKwArgs): """ Class for representing parameters of ``deploy_contract`` """ salt_nonce: typing.NotRequired[u256 | typing.Literal[0]] """ *iff* it is provided and does not equal to :math:`0` then ``Address`` of deployed contract will be known ahead of time. It will depend on this field """
@typing.overload def deploy_contract( *, code: bytes, args: collections.abc.Sequence[typing.Any] = [], kwargs: collections.abc.Mapping[str, typing.Any] = {}, ) -> None: ... @typing.overload def deploy_contract( *, code: bytes, args: collections.abc.Sequence[typing.Any] = [], salt_nonce: typing.Literal[0], kwargs: collections.abc.Mapping[str, typing.Any] = {}, ) -> Address: ...
[docs] def deploy_contract( *, code: bytes, args: collections.abc.Sequence[typing.Any] = [], kwargs: collections.abc.Mapping[str, typing.Any] = {}, **data: typing.Unpack[DeploymentTransactionDataKwArgs], ) -> Address | None: """ Function for deploying new genvm contracts :param code: code (i.e. contents of a python file) of the contract :returns: address of new contract *iff* ``salt_nonce`` was provided """ salt_nonce = data.setdefault('salt_nonce', u256(0)) wasi.deploy_contract( calldata.encode( { 'args': args, 'kwargs': kwargs, } ), code, json.dumps(data), ) if salt_nonce == 0: return None import genlayer.std as gl from genlayer.py._internal import create2_address return create2_address(gl.message.contract_account, salt_nonce, gl.message.chain_id)