From 911cc5ba12596819fe449aa1e7280918ce497e9d Mon Sep 17 00:00:00 2001 From: Eduardo Vasques Date: Tue, 18 Mar 2025 17:02:09 +0000 Subject: [PATCH 1/3] adds contract and project names to Projects and Instances in python --- python/src/skale_contracts/instance.py | 14 +-- python/src/skale_contracts/network.py | 6 +- python/src/skale_contracts/project.py | 28 ++++-- python/src/skale_contracts/project_factory.py | 11 ++- .../projects/config_controller.py | 26 ++++-- .../src/skale_contracts/projects/context.py | 28 +++--- .../src/skale_contracts/projects/erc1820.py | 22 +++-- .../src/skale_contracts/projects/etherbase.py | 23 +++-- .../skale_contracts/projects/filestorage.py | 23 +++-- python/src/skale_contracts/projects/ima.py | 87 ++++++++++++++----- .../skale_contracts/projects/marionette.py | 23 +++-- .../src/skale_contracts/projects/paymaster.py | 25 ++++-- .../projects/skale_allocator.py | 31 +++++-- .../skale_contracts/projects/skale_manager.py | 58 +++++++++++-- python/src/skale_contracts/types.py | 7 ++ 15 files changed, 299 insertions(+), 113 deletions(-) create mode 100644 python/src/skale_contracts/types.py diff --git a/python/src/skale_contracts/instance.py b/python/src/skale_contracts/instance.py index 8d08595..197e8bd 100644 --- a/python/src/skale_contracts/instance.py +++ b/python/src/skale_contracts/instance.py @@ -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""" diff --git a/python/src/skale_contracts/network.py b/python/src/skale_contracts/network.py index 789658d..4260d01 100644 --- a/python/src/skale_contracts/network.py +++ b/python/src/skale_contracts/network.py @@ -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) diff --git a/python/src/skale_contracts/project.py b/python/src/skale_contracts/project.py index 66d331e..17b7a7d 100644 --- a/python/src/skale_contracts/project.py +++ b/python/src/skale_contracts/project.py @@ -4,13 +4,16 @@ from __future__ import annotations from abc import ABC, abstractmethod +from enum import StrEnum 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 @@ -19,6 +22,21 @@ 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]: diff --git a/python/src/skale_contracts/project_factory.py b/python/src/skale_contracts/project_factory.py index 3541c6b..b7e84c2 100644 --- a/python/src/skale_contracts/project_factory.py +++ b/python/src/skale_contracts/project_factory.py @@ -1,17 +1,19 @@ """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) @@ -19,7 +21,8 @@ } -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) diff --git a/python/src/skale_contracts/projects/config_controller.py b/python/src/skale_contracts/projects/config_controller.py index c041d9d..12e74b3 100644 --- a/python/src/skale_contracts/projects/config_controller.py +++ b/python/src/skale_contracts/projects/config_controller.py @@ -1,18 +1,24 @@ """Module connects config-controller project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address 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 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,7 +29,7 @@ class ConfigControllerInstance(Instance): def get_contract_address( self, - name: str, + name: ContextControllerContract, *args: str | Address | ChecksumAddress ) -> Address: if name in self.PREDEPLOYED: @@ -31,14 +37,18 @@ def get_contract_address( 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: diff --git a/python/src/skale_contracts/projects/context.py b/python/src/skale_contracts/projects/context.py index 9d89c70..3055319 100644 --- a/python/src/skale_contracts/projects/context.py +++ b/python/src/skale_contracts/projects/context.py @@ -1,20 +1,26 @@ """Module connects context-contract project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address 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 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' @@ -22,11 +28,11 @@ def __init__(self, project: Project, address: 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: @@ -34,25 +40,25 @@ def get_contract_address( 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: diff --git a/python/src/skale_contracts/projects/erc1820.py b/python/src/skale_contracts/projects/erc1820.py index 91ec7d2..8d661ee 100644 --- a/python/src/skale_contracts/projects/erc1820.py +++ b/python/src/skale_contracts/projects/erc1820.py @@ -1,18 +1,24 @@ """Module connects erc1820 project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address 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 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,7 +32,7 @@ def _get_version(self) -> str: def get_contract_address( self, - name: str, + name: Erc1820Contract, *args: str | Address | ChecksumAddress ) -> Address: if name in self.PREDEPLOYED: @@ -34,14 +40,14 @@ def get_contract_address( 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: diff --git a/python/src/skale_contracts/projects/etherbase.py b/python/src/skale_contracts/projects/etherbase.py index 24f8a04..65a815b 100644 --- a/python/src/skale_contracts/projects/etherbase.py +++ b/python/src/skale_contracts/projects/etherbase.py @@ -1,18 +1,24 @@ """Module connects etherbase project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address 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 if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress -class EtherbaseInstance(Instance): +class EtherbaseContract(StrEnum): + """Defines contract names for etherbase project""" + ETHERBASE = "Etherbase" + + +class EtherbaseInstance(Instance[EtherbaseContract]): """Represents instance of etherbase""" PREDEPLOYED: dict[str, Address] = { @@ -23,7 +29,7 @@ class EtherbaseInstance(Instance): def get_contract_address( self, - name: str, + name: EtherbaseContract, *args: str | Address | ChecksumAddress ) -> Address: if name in self.PREDEPLOYED: @@ -31,14 +37,15 @@ def get_contract_address( raise RuntimeError(f"Can't get address of {name} contract") -class EtherbaseProject(Project): +class EtherbaseProject(Project[EtherbaseContract]): """Represents etherbase project""" @staticmethod - def name() -> str: - return 'etherbase' + def name() -> SkaleProject: + return SkaleProject.ETHERBASE - def get_instance(self, alias_or_address: str) -> Instance: + def get_instance( + self, alias_or_address: str) -> Instance[EtherbaseContract]: if alias_or_address == PREDEPLOYED_ALIAS: return self.create_instance( EtherbaseInstance.PREDEPLOYED['Etherbase'] @@ -49,7 +56,7 @@ def get_instance(self, alias_or_address: str) -> Instance: def github_repo(self) -> str: return 'https://github.com/skalenetwork/etherbase/' - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> EtherbaseInstance: return EtherbaseInstance(self, address) def get_abi_filename(self, version: str) -> str: diff --git a/python/src/skale_contracts/projects/filestorage.py b/python/src/skale_contracts/projects/filestorage.py index 3383790..9267a0c 100644 --- a/python/src/skale_contracts/projects/filestorage.py +++ b/python/src/skale_contracts/projects/filestorage.py @@ -1,18 +1,24 @@ """Module connects filestorage project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address 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 if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress -class FilestorageInstance(Instance): +class FilestorageContract(StrEnum): + """Defines contract names for marionette project""" + FILE_STORAGE = "FileStorage" + + +class FilestorageInstance(Instance[FilestorageContract]): """Represents instance of filestorage""" PREDEPLOYED: dict[str, Address] = { @@ -23,7 +29,7 @@ class FilestorageInstance(Instance): def get_contract_address( self, - name: str, + name: FilestorageContract, *args: str | Address | ChecksumAddress ) -> Address: if name in self.PREDEPLOYED: @@ -31,14 +37,15 @@ def get_contract_address( raise RuntimeError(f"Can't get address of {name} contract") -class FilestorageProject(Project): +class FilestorageProject(Project[FilestorageContract]): """Represents filestorage project""" @staticmethod - def name() -> str: - return 'filestorage' + def name() -> SkaleProject: + return SkaleProject.FILESTORAGE - def get_instance(self, alias_or_address: str) -> Instance: + def get_instance( + self, alias_or_address: str) -> Instance[FilestorageContract]: if alias_or_address == PREDEPLOYED_ALIAS: return self.create_instance( FilestorageInstance.PREDEPLOYED['FileStorage'] @@ -49,7 +56,7 @@ def get_instance(self, alias_or_address: str) -> Instance: def github_repo(self) -> str: return 'https://github.com/skalenetwork/filestorage/' - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> FilestorageInstance: return FilestorageInstance(self, address) def get_abi_filename(self, version: str) -> str: diff --git a/python/src/skale_contracts/projects/ima.py b/python/src/skale_contracts/projects/ima.py index 0d7a409..aa82a00 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -1,12 +1,14 @@ """Module connects IMA to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address +from skale_contracts.types import ContractName from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance, DEFAULT_GET_VERSION_FUNCTION -from skale_contracts.project import Project +from skale_contracts.project import Project, SkaleProject from .skale_manager import CONTRACT_MANAGER_ABI @@ -20,9 +22,41 @@ ] -class ImaInstance(Instance): +class SchainImaContract(StrEnum): + """Defines contract names for schain-ima project""" + TOKEN_MANAGER_ETH = "TokenManagerEth" + TOKEN_MANAGER_ERC20 = "TokenManagerERC20" + TOKEN_MANAGER_ERC721 = "TokenManagerERC721" + TOKEN_MANAGER_ERC1155 = "TokenManagerERC1155" + # TOKEN_MANAGER_ERC721_WITH_META = "DepositBoxERC721WithMetadata" + PROXY_FOR_SCHAIN = "MessageProxyForSchain" + COMMUNITY_LOCKER = "CommunityLocker" + TOKEN_MANAGER_LINKER = "TokenManagerLinker" + ETH_ERC20 = "EthErc20" + KEY_STORAGE = "KeyStorage" + + +class MainnetImaContract(StrEnum): + """Defines contract names for mainnet-ima project""" + PROXY_FOR_MAINNET = "MessageProxyForMainnet" + COMMUNITY_POOL = "CommunityPool" + LINKER = "Linker" + DEPOSIT_BOX_ETH = "DepositBoxEth" + DEPOSIT_BOX_ERC20 = "DepositBoxERC20" + DEPOSIT_BOX_ERC721 = "DepositBoxERC721" + DEPOSIT_BOX_ERC1155 = "DepositBoxERC1155" + DEPOSIT_BOX_ERC721_WITH_META = "DepositBoxERC721WithMetadata" + + +class ImaInstance(Instance[ContractName]): """Represents instance of IMA""" - def __init__(self, project: Project, address: Address) -> None: + + def __init__( + self, + project: Project[ContractName], + address: Address + ) -> None: + super().__init__(project, address) self.message_proxy = self.web3.eth.contract( address=address, @@ -30,7 +64,7 @@ def __init__(self, project: Project, address: Address) -> None: ) -class ImaProject(Project): +class ImaProject(Project[ContractName]): """Represents IMA project""" @property @@ -38,22 +72,27 @@ def github_repo(self) -> str: return 'https://github.com/skalenetwork/ima/' -class MainnetImaInstance(ImaInstance): +class MainnetImaInstance(ImaInstance[MainnetImaContract]): """Represents IMA instance on mainnet""" - def __init__(self, project: Project, address: Address) -> None: + def __init__( + self, + project: Project[MainnetImaContract], + address: Address + ) -> None: + super().__init__(project, address) self._contract_manager: Contract | None = None def get_contract_address( self, - name: str, *args: str | Address | ChecksumAddress + name: MainnetImaContract, *args: str | Address | ChecksumAddress ) -> Address: if name == 'MessageProxyForMainnet': return self.address if name == 'CommunityPool': return to_canonical_address( - self.get_contract("MessageProxyForMainnet") + self.get_contract(MainnetImaContract.PROXY_FOR_MAINNET) .functions.communityPool().call() ) return to_canonical_address( @@ -67,7 +106,7 @@ def contract_manager(self) -> Contract: if self._contract_manager is None: self._contract_manager = self.web3.eth.contract( address=to_canonical_address( - self.get_contract("MessageProxyForMainnet") + self.get_contract(MainnetImaContract.PROXY_FOR_MAINNET) .functions.contractManagerOfSkaleManager().call() ), abi=CONTRACT_MANAGER_ABI @@ -75,21 +114,21 @@ def contract_manager(self) -> Contract: return self._contract_manager -class MainnetImaProject(ImaProject): +class MainnetImaProject(ImaProject[MainnetImaContract]): """Represents mainnet part of IMA project""" @staticmethod - def name() -> str: - return 'mainnet-ima' + def name() -> SkaleProject: + return SkaleProject.MAINNET_IMA - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> MainnetImaInstance: return MainnetImaInstance(self, address) def get_abi_filename(self, version: str) -> str: return f'mainnet-ima-{version}-abi.json' -class SchainImaInstance(ImaInstance): +class SchainImaInstance(ImaInstance[SchainImaContract]): """Represents IMA instance on schain""" PREDEPLOYED: dict[str, Address] = { @@ -120,7 +159,7 @@ class SchainImaInstance(ImaInstance): def get_contract_address( self, - name: str, + name: SchainImaContract, *args: str | Address | ChecksumAddress ) -> Address: if name in self.PREDEPLOYED: @@ -128,21 +167,27 @@ def get_contract_address( raise RuntimeError(f"Can't get address of {name} contract") -class SchainImaProject(ImaProject): +class SchainImaProject(ImaProject[SchainImaContract]): """Represents schain part of IMA project""" @staticmethod - def name() -> str: - return 'schain-ima' + def name() -> SkaleProject: + return SkaleProject.SCHAIN_IMA + + def get_instance( + self, + alias_or_address: str + ) -> Instance[SchainImaContract]: - def get_instance(self, alias_or_address: str) -> Instance: if alias_or_address == PREDEPLOYED_ALIAS: return self.create_instance( - SchainImaInstance.PREDEPLOYED['MessageProxyForSchain'] + SchainImaInstance.PREDEPLOYED[ + SchainImaContract.PROXY_FOR_SCHAIN + ] ) return super().get_instance(alias_or_address) - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> SchainImaInstance: return SchainImaInstance(self, address) def get_abi_filename(self, version: str) -> str: diff --git a/python/src/skale_contracts/projects/marionette.py b/python/src/skale_contracts/projects/marionette.py index fa5fc97..020cc9a 100644 --- a/python/src/skale_contracts/projects/marionette.py +++ b/python/src/skale_contracts/projects/marionette.py @@ -1,18 +1,24 @@ """Module connects marionette project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address 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 if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress -class MarionetteInstance(Instance): +class MarionetteContract(StrEnum): + """Defines contract names for marionette project""" + MARIONETTE = "Marionette" + + +class MarionetteInstance(Instance[MarionetteContract]): """Represents instance of marionette""" PREDEPLOYED: dict[str, Address] = { @@ -23,7 +29,7 @@ class MarionetteInstance(Instance): def get_contract_address( self, - name: str, + name: MarionetteContract, *args: str | Address | ChecksumAddress ) -> Address: if name in self.PREDEPLOYED: @@ -31,14 +37,15 @@ def get_contract_address( raise RuntimeError(f"Can't get address of {name} contract") -class MarionetteProject(Project): +class MarionetteProject(Project[MarionetteContract]): """Represents marionette project""" @staticmethod - def name() -> str: - return 'marionette' + def name() -> SkaleProject: + return SkaleProject.MARIONETTE - def get_instance(self, alias_or_address: str) -> Instance: + def get_instance( + self, alias_or_address: str) -> Instance[MarionetteContract]: if alias_or_address == PREDEPLOYED_ALIAS: return self.create_instance( MarionetteInstance.PREDEPLOYED['Marionette'] @@ -49,7 +56,7 @@ def get_instance(self, alias_or_address: str) -> Instance: def github_repo(self) -> str: return 'https://github.com/skalenetwork/marionette/' - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> MarionetteInstance: return MarionetteInstance(self, address) def get_abi_filename(self, version: str) -> str: diff --git a/python/src/skale_contracts/projects/paymaster.py b/python/src/skale_contracts/projects/paymaster.py index ccaad15..7b1821e 100644 --- a/python/src/skale_contracts/projects/paymaster.py +++ b/python/src/skale_contracts/projects/paymaster.py @@ -1,45 +1,54 @@ """Module connects paymaster project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.instance import Instance -from skale_contracts.project import Project +from skale_contracts.project import Project, SkaleProject if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress -class PaymasterInstance(Instance): +class PaymasterContract(StrEnum): + """Defines contract names for paymaster project""" + PAYMASTER = "Paymaster" + PAYMASTER_ACCESS_MANAGER = "PaymasterAccessManager" + FAST_FORWARD_PAYMASTER = "FastForwardPaymaster" + + +class PaymasterInstance(Instance[PaymasterContract]): """Represents instance of paymaster""" def get_contract_address( self, - name: str, + name: PaymasterContract, *args: str | Address | ChecksumAddress + ) -> Address: if name in {"Paymaster", "FastForwardPaymaster"}: return self.address if name == "PaymasterAccessManager": return to_canonical_address( - self.get_contract("Paymaster") + self.get_contract(PaymasterContract.PAYMASTER) .functions.authority().call() ) raise RuntimeError(f"Can't get address of {name} contract") -class PaymasterProject(Project): +class PaymasterProject(Project[PaymasterContract]): """Represents paymaster project""" @staticmethod - def name() -> str: - return 'paymaster' + def name() -> SkaleProject: + return SkaleProject.PAYMASTER @property def github_repo(self) -> str: return 'https://github.com/skalenetwork/paymaster/' - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> PaymasterInstance: return PaymasterInstance(self, address) def get_abi_filename(self, version: str) -> str: diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index dcc1350..7d5d5bc 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -1,26 +1,39 @@ """Module connects skale-allocator project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.instance import Instance -from skale_contracts.project import Project +from skale_contracts.project import Project, SkaleProject if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress -class SkaleAllocatorInstance(Instance): +class SkaleAllocatorContract(StrEnum): + """Defines contract names for skale-allocator project""" + ALLOCATOR = "Allocator" + ESCROW = "Escrow" + + +class SkaleAllocatorInstance(Instance[SkaleAllocatorContract]): """Represents instance of skale-allocator""" - def __init__(self, project: Project, address: Address) -> None: + + def __init__( + self, + project: Project[SkaleAllocatorContract], + address: Address + ) -> None: + super().__init__(project, address) - self.allocator = self.get_contract("Allocator") + self.allocator = self.get_contract(SkaleAllocatorContract.ALLOCATOR) def get_contract_address( self, - name: str, + name: SkaleAllocatorContract, *args: str | Address | ChecksumAddress ) -> Address: if name == 'Allocator': @@ -39,18 +52,18 @@ def _get_escrow(self, beneficiary: Address) -> Address: ) -class SkaleAllocatorProject(Project): +class SkaleAllocatorProject(Project[SkaleAllocatorContract]): """Represents skale-allocator project""" @staticmethod - def name() -> str: - return 'skale-allocator' + def name() -> SkaleProject: + return SkaleProject.SKALE_ALLOCATOR @property def github_repo(self) -> str: return 'https://github.com/skalenetwork/skale-allocator/' - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> SkaleAllocatorInstance: return SkaleAllocatorInstance(self, address) def get_abi_filename(self, version: str) -> str: diff --git a/python/src/skale_contracts/projects/skale_manager.py b/python/src/skale_contracts/projects/skale_manager.py index 1068e85..2322217 100644 --- a/python/src/skale_contracts/projects/skale_manager.py +++ b/python/src/skale_contracts/projects/skale_manager.py @@ -1,11 +1,12 @@ """Module connects skale-manager project to the SKALE contracts library""" from __future__ import annotations +from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.instance import Instance, DEFAULT_GET_VERSION_FUNCTION -from skale_contracts.project import Project +from skale_contracts.project import Project, SkaleProject if TYPE_CHECKING: @@ -45,9 +46,48 @@ ] -class SkaleManagerInstance(Instance): +class SkaleManagerContract(StrEnum): + """Defines contract names for skale-manager project""" + CONTRACT_MANAGER = "ContractManager" + + DELEGATION_CONTROLLER = "DelegationController" + DELEGATION_PERIOD_MANAGER = "DelegationPeriodManager" + DISTRIBUTOR = "Distributor" + PUNISHER = "Punisher" + SLASHING_TABLE = "SlashingTable" + TIME_HELPERS = "TimeHelpers" + TOKEN_STATE = "TokenState" + VALIDATOR_SERVICE = "ValidatorService" + + CONSTANTS_HOLDER = "ConstantsHolder" + NODES = "Nodes" + NODE_ROTATION = "NodeRotation" + SCHAINS_INTERNAL = "SchainsInternal" + SCHAINS = "Schains" + DECRYPTION = "Decryption" + ECDH = "ECDH" + KEY_STORAGE = "KeyStorage" + SKALE_DKG = "SkaleDKG" + SKALE_VERIFIER = "SkaleVerifier" + SKALE_MANAGER = "SkaleManager" + BOUNTY = "Bounty" + BOUNTY_V2 = "BountyV2" + WALLETS = "Wallets" + SYNC_MANAGER = "SyncManager" + PAYMASTER_CONTROLLER = "PaymasterController" + TIME_HELPERS_WITH_DEBUG = "TimeHelpersWithDebug" + SKALE_TOKEN = "SkaleToken" + + +class SkaleManagerInstance(Instance[SkaleManagerContract]): """Represents instance of skale-manager""" - def __init__(self, project: Project, address: Address) -> None: + + def __init__( + self, + project: Project[SkaleManagerContract], + address: Address + ) -> None: + super().__init__(project, address) self.skale_manager = self.web3.eth.contract( address=address, @@ -61,12 +101,12 @@ def __init__(self, project: Project, address: Address) -> None: ) self.custom_names = { 'BountyV2': 'Bounty', - 'TimeHelpersWithDebug': 'TimeHelpers' + 'TimeHelpersWithDebug': 'TimeHelpers' } def get_contract_address( self, - name: str, + name: SkaleManagerContract, *args: str | Address | ChecksumAddress ) -> Address: return to_canonical_address( @@ -81,18 +121,18 @@ def _actual_name(self, name: str) -> str: return name -class SkaleManagerProject(Project): +class SkaleManagerProject(Project[SkaleManagerContract]): """Represents skale-manager project""" @staticmethod - def name() -> str: - return 'skale-manager' + def name() -> SkaleProject: + return SkaleProject.SKALE_MANAGER @property def github_repo(self) -> str: return 'https://github.com/skalenetwork/skale-manager/' - def create_instance(self, address: Address) -> Instance: + def create_instance(self, address: Address) -> SkaleManagerInstance: return SkaleManagerInstance(self, address) def get_abi_filename(self, version: str) -> str: diff --git a/python/src/skale_contracts/types.py b/python/src/skale_contracts/types.py new file mode 100644 index 0000000..e30cd6f --- /dev/null +++ b/python/src/skale_contracts/types.py @@ -0,0 +1,7 @@ +"""Module for defining package types""" + +from enum import StrEnum +from typing import TypeVar + + +ContractName = TypeVar('ContractName', bound=StrEnum) From 2dca5f8e5adf4c6c9dcbd69a669c9666f12ae2ba Mon Sep 17 00:00:00 2001 From: Eduardo Vasques Date: Tue, 18 Mar 2025 17:02:27 +0000 Subject: [PATCH 2/3] adds contract and project names to Projects and Instances in typescript --- typescript/base/src/metadata.ts | 4 +- typescript/base/src/network.ts | 3 +- typescript/base/src/project.ts | 10 +++ typescript/base/src/projects/factory.ts | 62 +++++++------------ .../ima/mainnet/MainnetImaInstance.ts | 24 +++++-- .../projects/ima/mainnet/MainnetImaProject.ts | 14 ++++- .../projects/ima/schain/SchainImaInstance.ts | 3 +- .../projects/ima/schain/SchainImaProject.ts | 32 ++++++++-- .../projects/paymaster/paymasterInstance.ts | 21 ++++--- .../projects/paymaster/paymasterProject.ts | 8 ++- .../skale-allocator/skaleAllocatorInstance.ts | 14 +++-- .../skale-allocator/skaleAllocatorProject.ts | 6 ++ .../skale-manager/skaleManagerInstance.ts | 5 +- .../skale-manager/skaleManagerProject.ts | 35 ++++++++++- 14 files changed, 171 insertions(+), 70 deletions(-) diff --git a/typescript/base/src/metadata.ts b/typescript/base/src/metadata.ts index 85790fb..952eb4b 100644 --- a/typescript/base/src/metadata.ts +++ b/typescript/base/src/metadata.ts @@ -2,6 +2,8 @@ import { METADATA_FILENAME, REPOSITORY_URL } from "./domain/constants"; import { MetadataIsNotDownloaded } from "./domain/errors/metadata/metadataIsNotDownloaded"; +import { SkaleProjectName } from "./project"; + import axios from "axios"; @@ -12,7 +14,7 @@ export type NetworkMetadata = { } export type ProjectMetadata = { - name: string; + name: SkaleProjectName; path: string; } diff --git a/typescript/base/src/network.ts b/typescript/base/src/network.ts index 697ddc1..b541d58 100644 --- a/typescript/base/src/network.ts +++ b/typescript/base/src/network.ts @@ -1,6 +1,7 @@ import { Adapter } from "./adapter"; import { RetryAdapter } from "./retryAdapter"; import { SkaleContracts } from "./skaleContracts"; +import { SkaleProjectName } from "./project"; import { createProject } from "./projects/factory"; @@ -21,7 +22,7 @@ export class Network { return this.networkAdapter; } - getProject (name: string) { + getProject (name: SkaleProjectName) { return createProject( this, name diff --git a/typescript/base/src/project.ts b/typescript/base/src/project.ts index 46fe37c..db95c3f 100644 --- a/typescript/base/src/project.ts +++ b/typescript/base/src/project.ts @@ -15,6 +15,16 @@ import { import { ProjectMetadata } from "./metadata"; import { REPOSITORY_URL } from "./domain/constants"; +export enum SkaleProject { + MAINNET_IMA = "mainnet-ima", + SCHAIN_IMA = "schain-ima", + PAYMASTER = "paymaster", + SKALE_ALLOCATOR = "skale-allocator", + SKALE_MANAGER = "skale-manager", +} +export type SkaleProjectName = `${SkaleProject}`; + + const alternativeVersionsGenerator = function *alternativeVersionsGenerator (version: string) { const semVersion = semver.parse(version); diff --git a/typescript/base/src/projects/factory.ts b/typescript/base/src/projects/factory.ts index 2aa8beb..d85bc37 100644 --- a/typescript/base/src/projects/factory.ts +++ b/typescript/base/src/projects/factory.ts @@ -1,7 +1,7 @@ +import { Project, SkaleProject, SkaleProjectName } from "../project"; import { MainnetImaProject } from "./ima/mainnet/MainnetImaProject"; import { Network } from "../network"; import { PaymasterProject } from "./paymaster/paymasterProject"; -import { Project } from "../project"; import { ProjectNotFoundError } from "../domain/errors/project/projectNotFoundError"; @@ -10,59 +10,43 @@ import { SkaleAllocatorProject } from "./skale-allocator/skaleAllocatorProject"; import { SkaleManagerProject } from "./skale-manager/skaleManagerProject"; -export const projects = { - "mainnetIma": { - "name": "mainnet-ima", - "path": "mainnet-ima" - }, - "paymaster": { - "name": "paymaster", - "path": "paymaster" - }, - "schainIma": { - "name": "schain-ima", - "path": "schain-ima" - }, - "skaleAllocator": { - "name": "skale-allocator", - "path": "skale-allocator" - }, - "skaleManager": { - "name": "skale-manager", - "path": "skale-manager" - } -}; - export const createProject = function createProject ( network: Network, - name: string + name: SkaleProjectName ): Project { - if (name === projects.skaleManager.name) { - return new SkaleManagerProject( + const metadata = { + name, + "path": name + }; + switch (name) { + case SkaleProject.MAINNET_IMA: + return new MainnetImaProject( network, - projects.skaleManager + metadata ); - } else if (name === projects.mainnetIma.name) { - return new MainnetImaProject( + case SkaleProject.PAYMASTER: + return new PaymasterProject( network, - projects.mainnetIma + metadata ); - } else if (name === projects.schainIma.name) { + case SkaleProject.SCHAIN_IMA: return new SchainImaProject( network, - projects.schainIma + metadata ); - } else if (name === projects.skaleAllocator.name) { + case SkaleProject.SKALE_ALLOCATOR: return new SkaleAllocatorProject( network, - projects.skaleAllocator + metadata ); - } else if (name === projects.paymaster.name) { - return new PaymasterProject( + case SkaleProject.SKALE_MANAGER: + return new SkaleManagerProject( network, - projects.paymaster + metadata ); + default: + // eslint-disable-next-line max-len + throw new ProjectNotFoundError(`Project with name ${name} is unknown`); } - throw new ProjectNotFoundError(`Project with name ${name} is unknown`); }; diff --git a/typescript/base/src/projects/ima/mainnet/MainnetImaInstance.ts b/typescript/base/src/projects/ima/mainnet/MainnetImaInstance.ts index f6c9e35..0f1181f 100644 --- a/typescript/base/src/projects/ima/mainnet/MainnetImaInstance.ts +++ b/typescript/base/src/projects/ima/mainnet/MainnetImaInstance.ts @@ -1,3 +1,7 @@ +import { + MainnetImaContract, + MainnetImaContractName +} from "./MainnetImaProject"; import { ContractAddress } from "../../../domain/types"; import { ContractData } from "../../../adapter"; import { ImaInstance } from "../ImaInstance"; @@ -30,15 +34,21 @@ export class MainnetImaInstance extends ImaInstance { private contractManager: ContractData | undefined; - async getContractAddress (name: string): Promise { - if (name === "MessageProxyForMainnet") { + async getContractAddress ( + name: MainnetImaContractName + ): Promise { + if (name === MainnetImaContract.PROXY_FOR_MAINNET) { return Promise.resolve(this.mainContractAddress); - } else if (name === "CommunityPool") { + } else if (name === MainnetImaContract.COMMUNITY_POOL) { return this.project.network.adapter.makeCall( { - "abi": await this.getContractAbi("MessageProxyForMainnet"), + "abi": await this.getContractAbi( + MainnetImaContract.PROXY_FOR_MAINNET + ), "address": - await this.getContractAddress("MessageProxyForMainnet") + await this.getContractAddress( + MainnetImaContract.PROXY_FOR_MAINNET + ) }, { "args": [], @@ -63,7 +73,9 @@ export class MainnetImaInstance extends await this.project.network.adapter.makeCall( { "abi": - await this.getContractAbi("MessageProxyForMainnet"), + await this.getContractAbi( + MainnetImaContract.PROXY_FOR_MAINNET + ), "address": this.mainContractAddress }, { diff --git a/typescript/base/src/projects/ima/mainnet/MainnetImaProject.ts b/typescript/base/src/projects/ima/mainnet/MainnetImaProject.ts index 5402e93..2f92f68 100644 --- a/typescript/base/src/projects/ima/mainnet/MainnetImaProject.ts +++ b/typescript/base/src/projects/ima/mainnet/MainnetImaProject.ts @@ -3,9 +3,21 @@ import { ImaProject } from "../ImaProject"; import { Instance } from "../../../instance"; import { MainnetImaInstance } from "./MainnetImaInstance"; +export enum MainnetImaContract { + PROXY_FOR_MAINNET = "MessageProxyForMainnet", + COMMUNITY_POOL = "CommunityPool", + LINKER = "Linker", + DEPOSIT_BOX_ETH = "DepositBoxEth", + DEPOSIT_BOX_ERC20 = "DepositBoxERC20", + DEPOSIT_BOX_ERC721 = "DepositBoxERC721", + DEPOSIT_BOX_ERC1155 = "DepositBoxERC1155", + DEPOSIT_BOX_ERC721_WITH_META = "DepositBoxERC721WithMetadata", +} +export type MainnetImaContractName = `${MainnetImaContract}`; + export class MainnetImaProject extends ImaProject { - mainContractName = "MessageProxyForMainnet"; + mainContractName = MainnetImaContract.PROXY_FOR_MAINNET; getAbiFilename (version: string) { return `${this.metadata.name}-${version}-abi.json`; diff --git a/typescript/base/src/projects/ima/schain/SchainImaInstance.ts b/typescript/base/src/projects/ima/schain/SchainImaInstance.ts index 0493511..b03a617 100644 --- a/typescript/base/src/projects/ima/schain/SchainImaInstance.ts +++ b/typescript/base/src/projects/ima/schain/SchainImaInstance.ts @@ -1,5 +1,6 @@ import { ContractAddress } from "../../../domain/types"; import { ImaInstance } from "../ImaInstance"; +import { SchainImaContractName } from "./SchainImaProject"; export class SchainImaInstance extends @@ -51,7 +52,7 @@ export class SchainImaInstance extends ] ]); - getContractAddress (name: string): Promise { + getContractAddress (name: SchainImaContractName): Promise { if (name in this.addressContainer) { return Promise.resolve(this.addressContainer[name]); } diff --git a/typescript/base/src/projects/ima/schain/SchainImaProject.ts b/typescript/base/src/projects/ima/schain/SchainImaProject.ts index b85f427..1527cc6 100644 --- a/typescript/base/src/projects/ima/schain/SchainImaProject.ts +++ b/typescript/base/src/projects/ima/schain/SchainImaProject.ts @@ -3,27 +3,51 @@ import { ContractAddressMap, MainContractAddress } from "../../../domain/types"; + import { ImaProject } from "../ImaProject"; import { Instance } from "../../../instance"; -import { PREDEPLOYED_ALIAS } from "../../../domain/constants"; +import { + PREDEPLOYED_ALIAS +} from "../../../domain/constants"; import { SchainImaInstance } from "./SchainImaInstance"; + +export enum SchainImaContract { + TOKEN_MANAGER_ETH = "TokenManagerEth", + TOKEN_MANAGER_ERC20 = "TokenManagerERC20", + TOKEN_MANAGER_ERC721 = "TokenManagerERC721", + TOKEN_MANAGER_ERC1155 = "TokenManagerERC1155", + // TOKEN_MANAGER_ERC721_WITH_META = "DepositBoxERC721WithMetadata", + PROXY_FOR_SCHAIN = "MessageProxyForSchain", + COMMUNITY_LOCKER = "CommunityLocker", + TOKEN_MANAGER_LINKER = "TokenManagerLinker", + ETH_ERC20 = "EthErc20", + KEY_STORAGE = "KeyStorage" +} +export type SchainImaContractName = `${SchainImaContract}`; + export class SchainImaProject extends ImaProject { - mainContractName = "MessageProxyForSchain"; + mainContractName = SchainImaContract.PROXY_FOR_SCHAIN; getAbiFilename (version: string) { return `${this.metadata.name}-${version}-abi.json`; } getInstance ( - aliasOrAddress: string | MainContractAddress | ContractAddressMap + aliasOrAddress: + | SchainImaContractName + | MainContractAddress + | ContractAddressMap + | typeof PREDEPLOYED_ALIAS ) { if (aliasOrAddress === PREDEPLOYED_ALIAS) { return this.createInstance(SchainImaInstance.PREDEPLOYED. get(this.mainContractName)! as ContractAddress); } - return super.getInstance(aliasOrAddress); + return ( + super.getInstance(aliasOrAddress) as SchainImaInstance + ); } createInstance (address: MainContractAddress | ContractAddressMap) diff --git a/typescript/base/src/projects/paymaster/paymasterInstance.ts b/typescript/base/src/projects/paymaster/paymasterInstance.ts index a0781f8..da62e5b 100644 --- a/typescript/base/src/projects/paymaster/paymasterInstance.ts +++ b/typescript/base/src/projects/paymaster/paymasterInstance.ts @@ -1,20 +1,25 @@ import { - ContractAddress, - ContractName + PaymasterContract, + PaymasterContractName +} from "./paymasterProject"; + +import { + ContractAddress } from "../../domain/types"; import { Instance } from "../../instance"; - export class PaymasterInstance extends Instance { - async getContractAddress (name: ContractName): Promise { + async getContractAddress ( + name: PaymasterContractName + ): Promise { if ([ - "Paymaster", - "FastForwardPaymaster" - ].includes(name)) { + PaymasterContract.PAYMASTER, + PaymasterContract.FAST_FORWARD_PAYMASTER + ].includes(name as PaymasterContract)) { return this.mainContractAddress; } - if (name === "PaymasterAccessManager") { + if (name === PaymasterContract.PAYMASTER_ACCESS_MANAGER) { return await this.callPaymaster( "authority", [] diff --git a/typescript/base/src/projects/paymaster/paymasterProject.ts b/typescript/base/src/projects/paymaster/paymasterProject.ts index 5eac072..b69ce64 100644 --- a/typescript/base/src/projects/paymaster/paymasterProject.ts +++ b/typescript/base/src/projects/paymaster/paymasterProject.ts @@ -2,12 +2,18 @@ import { ContractAddressMap, MainContractAddress } from "../../domain/types"; import { Instance } from "../../instance"; import { PaymasterInstance } from "./paymasterInstance"; import { Project } from "../../project"; +export enum PaymasterContract { + PAYMASTER = "Paymaster", + PAYMASTER_ACCESS_MANAGER = "PaymasterAccessManager", + FAST_FORWARD_PAYMASTER = "FastForwardPaymaster" +} +export type PaymasterContractName = `${PaymasterContract}`; export class PaymasterProject extends Project { githubRepo = "https://github.com/skalenetwork/paymaster/"; - mainContractName = "Paymaster"; + mainContractName = PaymasterContract.PAYMASTER; createInstance (address: MainContractAddress | ContractAddressMap) : Instance { diff --git a/typescript/base/src/projects/skale-allocator/skaleAllocatorInstance.ts b/typescript/base/src/projects/skale-allocator/skaleAllocatorInstance.ts index c032db2..c41e313 100644 --- a/typescript/base/src/projects/skale-allocator/skaleAllocatorInstance.ts +++ b/typescript/base/src/projects/skale-allocator/skaleAllocatorInstance.ts @@ -1,20 +1,22 @@ import { - ContractAddress, - ContractName + SkaleAllocatorContract, + SkaleAllocatorContractName +} from "./skaleAllocatorProject"; +import { + ContractAddress } from "../../domain/types"; import { Instance } from "../../instance"; - export class SkaleAllocatorInstance extends Instance { getContractAddress ( - name: ContractName, + name: SkaleAllocatorContractName, args?: unknown[] ): Promise { - if (name === "Allocator") { + if (name === SkaleAllocatorContract.ALLOCATOR) { return Promise.resolve(this.mainContractAddress); } - if (name === "Escrow") { + if (name === SkaleAllocatorContract.ESCROW) { const firstArgument = 0; const beneficiary = args?.at(firstArgument) as string; if (!this.project.network.adapter.isAddress(beneficiary)) { diff --git a/typescript/base/src/projects/skale-allocator/skaleAllocatorProject.ts b/typescript/base/src/projects/skale-allocator/skaleAllocatorProject.ts index 359d032..95a9bc3 100644 --- a/typescript/base/src/projects/skale-allocator/skaleAllocatorProject.ts +++ b/typescript/base/src/projects/skale-allocator/skaleAllocatorProject.ts @@ -3,6 +3,12 @@ import { Instance } from "../../instance"; import { Project } from "../../project"; import { SkaleAllocatorInstance } from "./skaleAllocatorInstance"; +export enum SkaleAllocatorContract { + ALLOCATOR = "Allocator", + ESCROW = "Escrow", +} +export type SkaleAllocatorContractName = `${SkaleAllocatorContract}`; + export class SkaleAllocatorProject extends Project { githubRepo = "https://github.com/skalenetwork/skale-allocator/"; diff --git a/typescript/base/src/projects/skale-manager/skaleManagerInstance.ts b/typescript/base/src/projects/skale-manager/skaleManagerInstance.ts index d9e45b2..f321685 100644 --- a/typescript/base/src/projects/skale-manager/skaleManagerInstance.ts +++ b/typescript/base/src/projects/skale-manager/skaleManagerInstance.ts @@ -4,6 +4,7 @@ import { MainContractAddress } from "../../domain/types"; import { Instance } from "../../instance"; +import { SkaleManagerContractName } from "./skaleManagerProject"; const skaleManagerAbi = [ @@ -56,7 +57,9 @@ export class SkaleManagerInstance extends ) as string; } - async getContractAddress (name: ContractName): Promise { + async getContractAddress ( + name: SkaleManagerContractName + ): Promise { const contractManagerAbi = await this.getContractAbi("ContractManager"); const contractManagerAddress = await this.callSkaleManager( diff --git a/typescript/base/src/projects/skale-manager/skaleManagerProject.ts b/typescript/base/src/projects/skale-manager/skaleManagerProject.ts index c3894b9..a971052 100644 --- a/typescript/base/src/projects/skale-manager/skaleManagerProject.ts +++ b/typescript/base/src/projects/skale-manager/skaleManagerProject.ts @@ -3,11 +3,44 @@ import { Instance } from "../../instance"; import { Project } from "../../project"; import { SkaleManagerInstance } from "./skaleManagerInstance"; +export enum SkaleManagerContract { + CONTRACT_MANAGER = "ContractManager", + + DELEGATION_CONTROLLER = "DelegationController", + DELEGATION_PERIOD_MANAGER = "DelegationPeriodManager", + DISTRIBUTOR = "Distributor", + PUNISHER = "Punisher", + SLASHING_TABLE = "SlashingTable", + TIME_HELPERS = "TimeHelpers", + TOKEN_STATE = "TokenState", + VALIDATOR_SERVICE = "ValidatorService", + + CONSTANTS_HOLDER = "ConstantsHolder", + NODES = "Nodes", + NODE_ROTATION = "NodeRotation", + SCHAINS_INTERNAL = "SchainsInternal", + SCHAINS = "Schains", + DECRYPTION = "Decryption", + ECDH = "ECDH", + KEY_STORAGE = "KeyStorage", + SKALE_DKG = "SkaleDKG", + SKALE_VERIFIER = "SkaleVerifier", + SKALE_MANAGER = "SkaleManager", + BOUNTY = "Bounty", + BOUNTY_V2 = "BountyV2", + WALLETS = "Wallets", + SYNC_MANAGER = "SyncManager", + PAYMASTER_CONTROLLER = "PaymasterController", + TIME_HELPERS_WITH_DEBUG = "TimeHelpersWithDebug", + SKALE_TOKEN = "SkaleToken" +} +export type SkaleManagerContractName = `${SkaleManagerContract}`; + export class SkaleManagerProject extends Project { githubRepo = "https://github.com/skalenetwork/skale-manager/"; - mainContractName = "SkaleManager"; + mainContractName = SkaleManagerContract.SKALE_MANAGER; createInstance (address: MainContractAddress | ContractAddressMap) : Instance { From c432a8be91ae6701d3e79ae1130063316d8f0a19 Mon Sep 17 00:00:00 2001 From: Eduardo Vasques Date: Wed, 19 Mar 2025 11:19:29 +0000 Subject: [PATCH 3/3] introduce custom StrEnum for python =< 3.10 --- python/src/skale_contracts/project.py | 2 +- .../src/skale_contracts/projects/config_controller.py | 2 +- python/src/skale_contracts/projects/context.py | 2 +- python/src/skale_contracts/projects/erc1820.py | 2 +- python/src/skale_contracts/projects/etherbase.py | 2 +- python/src/skale_contracts/projects/filestorage.py | 2 +- python/src/skale_contracts/projects/ima.py | 2 +- python/src/skale_contracts/projects/marionette.py | 2 +- python/src/skale_contracts/projects/paymaster.py | 2 +- python/src/skale_contracts/projects/skale_allocator.py | 2 +- python/src/skale_contracts/projects/skale_manager.py | 2 +- python/src/skale_contracts/types.py | 10 +++++++++- 12 files changed, 20 insertions(+), 12 deletions(-) diff --git a/python/src/skale_contracts/project.py b/python/src/skale_contracts/project.py index 17b7a7d..5a1349e 100644 --- a/python/src/skale_contracts/project.py +++ b/python/src/skale_contracts/project.py @@ -4,7 +4,6 @@ from __future__ import annotations from abc import ABC, abstractmethod -from enum import StrEnum from itertools import count from typing import TYPE_CHECKING, Generator, Generic @@ -16,6 +15,7 @@ from .constants import REPOSITORY_URL, NETWORK_TIMEOUT from .instance import Instance, InstanceData +from .types import StrEnum if TYPE_CHECKING: from eth_typing import Address diff --git a/python/src/skale_contracts/projects/config_controller.py b/python/src/skale_contracts/projects/config_controller.py index 12e74b3..40af28d 100644 --- a/python/src/skale_contracts/projects/config_controller.py +++ b/python/src/skale_contracts/projects/config_controller.py @@ -1,13 +1,13 @@ """Module connects config-controller project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress diff --git a/python/src/skale_contracts/projects/context.py b/python/src/skale_contracts/projects/context.py index 3055319..f580915 100644 --- a/python/src/skale_contracts/projects/context.py +++ b/python/src/skale_contracts/projects/context.py @@ -1,12 +1,12 @@ """Module connects context-contract project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress diff --git a/python/src/skale_contracts/projects/erc1820.py b/python/src/skale_contracts/projects/erc1820.py index 8d661ee..09cb365 100644 --- a/python/src/skale_contracts/projects/erc1820.py +++ b/python/src/skale_contracts/projects/erc1820.py @@ -1,13 +1,13 @@ """Module connects erc1820 project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress diff --git a/python/src/skale_contracts/projects/etherbase.py b/python/src/skale_contracts/projects/etherbase.py index 65a815b..e8c66f5 100644 --- a/python/src/skale_contracts/projects/etherbase.py +++ b/python/src/skale_contracts/projects/etherbase.py @@ -1,13 +1,13 @@ """Module connects etherbase project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress diff --git a/python/src/skale_contracts/projects/filestorage.py b/python/src/skale_contracts/projects/filestorage.py index 9267a0c..efc7b14 100644 --- a/python/src/skale_contracts/projects/filestorage.py +++ b/python/src/skale_contracts/projects/filestorage.py @@ -1,10 +1,10 @@ """Module connects filestorage project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address +from skale_contracts.types import StrEnum from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject diff --git a/python/src/skale_contracts/projects/ima.py b/python/src/skale_contracts/projects/ima.py index aa82a00..4ab1e38 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -1,7 +1,6 @@ """Module connects IMA to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address @@ -9,6 +8,7 @@ from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance, DEFAULT_GET_VERSION_FUNCTION from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum from .skale_manager import CONTRACT_MANAGER_ABI diff --git a/python/src/skale_contracts/projects/marionette.py b/python/src/skale_contracts/projects/marionette.py index 020cc9a..5ee02c8 100644 --- a/python/src/skale_contracts/projects/marionette.py +++ b/python/src/skale_contracts/projects/marionette.py @@ -1,13 +1,13 @@ """Module connects marionette project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.constants import PREDEPLOYED_ALIAS from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress diff --git a/python/src/skale_contracts/projects/paymaster.py b/python/src/skale_contracts/projects/paymaster.py index 7b1821e..fb7363f 100644 --- a/python/src/skale_contracts/projects/paymaster.py +++ b/python/src/skale_contracts/projects/paymaster.py @@ -1,11 +1,11 @@ """Module connects paymaster project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: from eth_typing import Address, ChecksumAddress diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index 7d5d5bc..7adf5a6 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -1,12 +1,12 @@ """Module connects skale-allocator project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.instance import Instance from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: diff --git a/python/src/skale_contracts/projects/skale_manager.py b/python/src/skale_contracts/projects/skale_manager.py index 2322217..191f880 100644 --- a/python/src/skale_contracts/projects/skale_manager.py +++ b/python/src/skale_contracts/projects/skale_manager.py @@ -1,12 +1,12 @@ """Module connects skale-manager project to the SKALE contracts library""" from __future__ import annotations -from enum import StrEnum from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.instance import Instance, DEFAULT_GET_VERSION_FUNCTION from skale_contracts.project import Project, SkaleProject +from skale_contracts.types import StrEnum if TYPE_CHECKING: diff --git a/python/src/skale_contracts/types.py b/python/src/skale_contracts/types.py index e30cd6f..85dbb5b 100644 --- a/python/src/skale_contracts/types.py +++ b/python/src/skale_contracts/types.py @@ -1,7 +1,15 @@ """Module for defining package types""" -from enum import StrEnum +from enum import Enum from typing import TypeVar +class StrEnum(str, Enum): + """Defines custom StrEnum to be compatible with python 3.9 and 3.10""" + def __new__(cls, value: str) -> "StrEnum": + if not isinstance(value, str): + raise TypeError(f"{value!r} is not a valid {cls.__name__} value") + return str.__new__(cls, value) + + ContractName = TypeVar('ContractName', bound=StrEnum)