Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds list of project names and contract names to python and typescript #365

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions python/src/skale_contracts/instance.py
Original file line number Diff line number Diff line change
@@ -3,12 +3,14 @@
from __future__ import annotations
from abc import ABC, abstractmethod
import json
from typing import TYPE_CHECKING, Optional, cast
from typing import TYPE_CHECKING, Generic, Optional, cast
from attr import dataclass
from eth_typing import ChecksumAddress
from parver import Version as PyVersion
from semver.version import Version as SemVersion

from .types import ContractName


if TYPE_CHECKING:
from eth_typing import Address
@@ -40,9 +42,11 @@ def from_json(cls, data: str) -> InstanceData:
return cls(data=json.loads(data))


class Instance(ABC):
class Instance(Generic[ContractName], ABC):
"""Represents deployed instance of a smart contracts project"""
def __init__(self, project: Project, address: Address) -> None:
def __init__(
self, project: Project[ContractName], address: Address) -> None:

self._project = project
self._version: Optional[str] = None
self._abi: Optional[SkaleAbi] = None
@@ -90,14 +94,14 @@ def abi(self) -> SkaleAbi:
@abstractmethod
def get_contract_address(
self,
name: str,
name: ContractName,
*args: str | Address | ChecksumAddress
) -> Address:
"""Get address of the contract by it's name"""

def get_contract(
self,
name: str,
name: ContractName,
*args: str | Address | ChecksumAddress
) -> Contract:
"""Get Contract object of the contract by it's name"""
6 changes: 5 additions & 1 deletion python/src/skale_contracts/network.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,10 @@
from web3 import Web3
from web3.providers.base import BaseProvider

from .types import ContractName

from .project import SkaleProject

from .project_factory import create_project


@@ -23,7 +27,7 @@ def __init__(
self.web3 = Web3(provider)
self._skale_contracts = skale_contracts

def get_project(self, name: str) -> Project:
def get_project(self, name: SkaleProject) -> Project[ContractName]:
"""Get Project object by it's name"""
return create_project(self, name)

28 changes: 23 additions & 5 deletions python/src/skale_contracts/project.py
Original file line number Diff line number Diff line change
@@ -5,20 +5,38 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from itertools import count
from typing import TYPE_CHECKING, Generator
from typing import TYPE_CHECKING, Generator, Generic

from eth_utils.address import to_canonical_address
import requests
from semver.version import Version as SemVersion

from .types import ContractName

from .constants import REPOSITORY_URL, NETWORK_TIMEOUT
from .instance import Instance, InstanceData
from .types import StrEnum

if TYPE_CHECKING:
from eth_typing import Address
from .network import Network


class SkaleProject(StrEnum):
"""Defines project names"""
MAINNET_IMA = "mainnet-ima"
SCHAIN_IMA = "schain-ima"
PAYMASTER = "paymaster"
SKALE_ALLOCATOR = "skale-allocator"
SKALE_MANAGER = "skale-manager"
MARIONETTE = "marionette"
FILESTORAGE = "filestorage"
ETHERBASE = "etherbase"
ERC1820 = "erc1820"
CONTEXT_CONTRACT = "context-contract"
CONFIG_CONTROLLER = "config-controller"


def alternative_versions_generator(version: str) -> Generator[str, None, None]:
"""Provides versions that have compatible ABI"""
sem_version = SemVersion.parse(version)
@@ -31,7 +49,7 @@ def alternative_versions_generator(version: str) -> Generator[str, None, None]:
)


class Project(ABC):
class Project(Generic[ContractName], ABC):
"""Represents set of smart contracts known as project"""

def __init__(self, network: Network) -> None:
@@ -40,7 +58,7 @@ def __init__(self, network: Network) -> None:

@staticmethod
@abstractmethod
def name() -> str:
def name() -> SkaleProject:
"""Name of the project"""

@property
@@ -53,7 +71,7 @@ def folder(self) -> str:
"""Folder name with instances json files"""
return self.name()

def get_instance(self, alias_or_address: str) -> Instance:
def get_instance(self, alias_or_address: str) -> Instance[ContractName]:
"""Create instance object based on alias or address"""
if self.network.web3.is_address(alias_or_address):
address = to_canonical_address(alias_or_address)
@@ -106,7 +124,7 @@ def get_instance_data_url(self, alias: str) -> str:
raise ValueError('Network is unknown')

@abstractmethod
def create_instance(self, address: Address) -> Instance:
def create_instance(self, address: Address) -> Instance[ContractName]:
"""Create instance object based on known address"""

def get_abi_urls(self, version: str) -> list[str]:
11 changes: 7 additions & 4 deletions python/src/skale_contracts/project_factory.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
"""Module for creation of Project objects"""

from __future__ import annotations
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any
import inspect

from .project import Project
from .types import ContractName

from .project import Project, SkaleProject
from . import projects

if TYPE_CHECKING:
from .network import Network


projects_dict: dict[str, type[Project]] = {
projects_dict: dict[str, type[Project[Any]]] = {
project_type.name(): project_type
for _, project_type
in inspect.getmembers(projects, inspect.isclass)
if issubclass(project_type, Project)
}


def create_project(network: Network, name: str) -> Project:
def create_project(
network: Network, name: SkaleProject) -> Project[ContractName]:
"""Create Project object based on it's name"""
if name in projects_dict:
return projects_dict[name](network)
26 changes: 18 additions & 8 deletions python/src/skale_contracts/projects/config_controller.py
Original file line number Diff line number Diff line change
@@ -6,13 +6,19 @@

from skale_contracts.constants import PREDEPLOYED_ALIAS
from skale_contracts.instance import Instance
from skale_contracts.project import Project
from skale_contracts.project import Project, SkaleProject
from skale_contracts.types import StrEnum

if TYPE_CHECKING:
from eth_typing import Address, ChecksumAddress


class ConfigControllerInstance(Instance):
class ContextControllerContract(StrEnum):
"""Defines contract names for config-controller project"""
CONFIG_CONTROLLER = "ConfigController"


class ConfigControllerInstance(Instance[ContextControllerContract]):
"""Represents instance of config-controller"""

PREDEPLOYED: dict[str, Address] = {
@@ -23,22 +29,26 @@ class ConfigControllerInstance(Instance):

def get_contract_address(
self,
name: str,
name: ContextControllerContract,
*args: str | Address | ChecksumAddress
) -> Address:
if name in self.PREDEPLOYED:
return self.PREDEPLOYED[name]
raise RuntimeError(f"Can't get address of {name} contract")


class ConfigControllerProject(Project):
class ConfigControllerProject(Project[ContextControllerContract]):
"""Represents config-controller project"""

@staticmethod
def name() -> str:
return 'config-controller'
def name() -> SkaleProject:
return SkaleProject.CONFIG_CONTROLLER

def get_instance(
self,
alias_or_address: str
) -> Instance[ContextControllerContract]:

def get_instance(self, alias_or_address: str) -> Instance:
if alias_or_address == PREDEPLOYED_ALIAS:
return self.create_instance(
ConfigControllerInstance.PREDEPLOYED['ConfigController']
@@ -49,7 +59,7 @@ def get_instance(self, alias_or_address: str) -> Instance:
def github_repo(self) -> str:
return 'https://github.com/skalenetwork/config-controller/'

def create_instance(self, address: Address) -> Instance:
def create_instance(self, address: Address) -> ConfigControllerInstance:
return ConfigControllerInstance(self, address)

def get_abi_filename(self, version: str) -> str:
28 changes: 17 additions & 11 deletions python/src/skale_contracts/projects/context.py
Original file line number Diff line number Diff line change
@@ -5,54 +5,60 @@

from skale_contracts.constants import PREDEPLOYED_ALIAS
from skale_contracts.instance import Instance
from skale_contracts.project import Project
from skale_contracts.project import Project, SkaleProject
from skale_contracts.types import StrEnum

if TYPE_CHECKING:
from eth_typing import Address, ChecksumAddress


class ContextInstance(Instance):
class ContextContract(StrEnum):
"""Defines contract names for context-contract project"""
CONTEXT_CONTRACT = "ContextContract"


class ContextInstance(Instance[ContextContract]):
"""Represents instance of context-contract"""

def __init__(self, project: Project, address: Address):
def __init__(self, project: Project[ContextContract], address: Address):
super().__init__(project, address)
self.initial_version = '1.0.0-develop.5'

PREDEPLOYED: dict[str, Address] = {
name: to_canonical_address(address) for name, address in {
'ContextContract':
'0xD2001000000000000000000000000000000000D2'
}.items()}
}.items()}

def get_contract_address(
self,
name: str,
name: ContextContract,
*args: str | Address | ChecksumAddress
) -> Address:
if name in self.PREDEPLOYED:
return self.PREDEPLOYED[name]
raise RuntimeError(f"Can't get address of {name} contract")


class ContextProject(Project):
class ContextProject(Project[ContextContract]):
"""Represents context-contract project"""

@staticmethod
def name() -> str:
return 'context-contract'
def name() -> SkaleProject:
return SkaleProject.CONTEXT_CONTRACT

@property
def github_repo(self) -> str:
return 'https://github.com/skalenetwork/context-contract/'

def create_instance(self, address: Address) -> Instance:
def create_instance(self, address: Address) -> ContextInstance:
return ContextInstance(self, address)

def get_instance(self, alias_or_address: str) -> Instance:
def get_instance(self, alias_or_address: str) -> Instance[ContextContract]:
if alias_or_address == PREDEPLOYED_ALIAS:
return self.create_instance(
ContextInstance.PREDEPLOYED['ContextContract']
)
)
return super().get_instance(alias_or_address)

def get_abi_filename(self, version: str) -> str:
22 changes: 14 additions & 8 deletions python/src/skale_contracts/projects/erc1820.py
Original file line number Diff line number Diff line change
@@ -6,13 +6,19 @@

from skale_contracts.constants import PREDEPLOYED_ALIAS
from skale_contracts.instance import Instance
from skale_contracts.project import Project
from skale_contracts.project import Project, SkaleProject
from skale_contracts.types import StrEnum

if TYPE_CHECKING:
from eth_typing import Address, ChecksumAddress


class Erc1820Instance(Instance):
class Erc1820Contract(StrEnum):
"""Defines contract names for erc1820 project"""
ERC1820_REGISTRY = "ERC1820Registry"


class Erc1820Instance(Instance[Erc1820Contract]):
"""Represents instance of erc1820"""

def _get_version(self) -> str:
@@ -26,22 +32,22 @@ def _get_version(self) -> str:

def get_contract_address(
self,
name: str,
name: Erc1820Contract,
*args: str | Address | ChecksumAddress
) -> Address:
if name in self.PREDEPLOYED:
return self.PREDEPLOYED[name]
raise RuntimeError(f"Can't get address of {name} contract")


class Erc1820Project(Project):
class Erc1820Project(Project[Erc1820Contract]):
"""Represents erc1820 project"""

@staticmethod
def name() -> str:
return 'erc1820'
def name() -> SkaleProject:
return SkaleProject.ERC1820

def get_instance(self, alias_or_address: str) -> Instance:
def get_instance(self, alias_or_address: str) -> Instance[Erc1820Contract]:
if alias_or_address == PREDEPLOYED_ALIAS:
return self.create_instance(
Erc1820Instance.PREDEPLOYED['Erc1820']
@@ -52,7 +58,7 @@ def get_instance(self, alias_or_address: str) -> Instance:
def github_repo(self) -> str:
return 'https://github.com/skalenetwork/erc1820-predeployed/'

def create_instance(self, address: Address) -> Instance:
def create_instance(self, address: Address) -> Erc1820Instance:
return Erc1820Instance(self, address)

def get_abi_filename(self, version: str) -> str:
Loading
Loading