From 29a48448a92c82a23dc8e510d716fdc2b1b77f96 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 2 Apr 2024 16:49:47 +0300 Subject: [PATCH 01/11] Add skale-allocator project --- python/src/skale_contracts/instance.py | 16 ++++++++++------ python/src/skale_contracts/project_factory.py | 3 +++ python/src/skale_contracts/projects/__init__.py | 3 ++- python/src/skale_contracts/projects/ima.py | 11 ++++------- .../skale_contracts/projects/skale_manager.py | 9 +++------ 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/python/src/skale_contracts/instance.py b/python/src/skale_contracts/instance.py index 3c2a2f1..a3da474 100644 --- a/python/src/skale_contracts/instance.py +++ b/python/src/skale_contracts/instance.py @@ -3,8 +3,9 @@ from __future__ import annotations from abc import ABC, abstractmethod import json -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, cast from attr import dataclass +from eth_typing import ChecksumAddress from parver import Version as PyVersion from semver.version import Version as SemVersion @@ -83,16 +84,19 @@ def abi(self) -> SkaleAbi: return self._abi @abstractmethod - def get_contract_address(self, name: str) -> Address: + def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: """Get address of the contract by it's name""" - def get_contract(self, name: str) -> Contract: + def get_contract(self, name: str, *args: str|Address|ChecksumAddress) -> Contract: """Get Contract object of the contract by it's name""" - address = self.get_contract_address(name) + address = self.get_contract_address(name, *args) return self.web3.eth.contract(address=address, abi=self.abi[name]) # protected - @abstractmethod def _get_version(self) -> str: - pass + contract = self.web3.eth.contract( + address=self.address, + abi=[DEFAULT_GET_VERSION_FUNCTION] + ) + return cast(str, contract.functions.version().call()) diff --git a/python/src/skale_contracts/project_factory.py b/python/src/skale_contracts/project_factory.py index de376d5..8626b0b 100644 --- a/python/src/skale_contracts/project_factory.py +++ b/python/src/skale_contracts/project_factory.py @@ -18,6 +18,7 @@ class Projects: skale_manager = ProjectMetadata(name='skale-manager', path='skale-manager') mainnet_ima = ProjectMetadata(name='mainnet-ima', path='mainnet-ima') schain_ima = ProjectMetadata(name='schain-ima', path='schain-ima') + skale_allocator = ProjectMetadata(name='skale-allocator', path='skale-allocator') def create_project(network: Network, name: str) -> Project: @@ -28,4 +29,6 @@ def create_project(network: Network, name: str) -> Project: return projects.MainnetIma(network, Projects.mainnet_ima) if name == Projects.schain_ima.name: return projects.SchainIma(network, Projects.schain_ima) + if name == Projects.skale_allocator.name: + return projects.SkaleAllocator(network, Projects.skale_allocator) raise ValueError(f'Project with name {name} is unknown') diff --git a/python/src/skale_contracts/projects/__init__.py b/python/src/skale_contracts/projects/__init__.py index 7eb124c..cc88ec4 100644 --- a/python/src/skale_contracts/projects/__init__.py +++ b/python/src/skale_contracts/projects/__init__.py @@ -3,5 +3,6 @@ MainnetImaProject as MainnetIma, \ SchainImaProject as SchainIma from .skale_manager import SkaleManagerProject as SkaleManager +from .skale_allocator import SkaleAllocatorProject as SkaleAllocator -__all__ = ['MainnetIma', 'SchainIma', 'SkaleManager'] +__all__ = ['MainnetIma', 'SchainIma', 'SkaleAllocator', 'SkaleManager'] diff --git a/python/src/skale_contracts/projects/ima.py b/python/src/skale_contracts/projects/ima.py index 8574662..cab97be 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -1,8 +1,7 @@ """Module connects IMA to the SKALE contracts library""" from __future__ import annotations -from typing import cast, TYPE_CHECKING -from eth_typing import Address +from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.constants import PREDEPLOYED_ALIAS @@ -13,6 +12,7 @@ if TYPE_CHECKING: + from eth_typing import Address, ChecksumAddress from web3.contract.contract import Contract MESSAGE_PROXY_ABI = [ @@ -26,9 +26,6 @@ def __init__(self, project: Project, address: Address) -> None: super().__init__(project, address) self.message_proxy = self.web3.eth.contract(address=address, abi=MESSAGE_PROXY_ABI) - def _get_version(self) -> str: - return cast(str, self.message_proxy.functions.version().call()) - class ImaProject(Project): """Represents IMA project""" @@ -45,7 +42,7 @@ def __init__(self, project: Project, address: Address) -> None: super().__init__(project, address) self._contract_manager: Contract | None = None - def get_contract_address(self, name: str) -> Address: + def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: if name == 'MessageProxyForMainnet': return self.address if name == 'CommunityPool': @@ -101,7 +98,7 @@ class SchainImaInstance(ImaInstance): 'TokenManagerERC721WithMetadata': '0xd2AaA00a00000000000000000000000000000000' }.items()} - def get_contract_address(self, name: str) -> Address: + def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: if name in self.PREDEPLOYED: return self.PREDEPLOYED[name] raise RuntimeError(f"Can't get address of {name} contract") diff --git a/python/src/skale_contracts/projects/skale_manager.py b/python/src/skale_contracts/projects/skale_manager.py index 9cf8840..0733df8 100644 --- a/python/src/skale_contracts/projects/skale_manager.py +++ b/python/src/skale_contracts/projects/skale_manager.py @@ -1,7 +1,7 @@ """Module connects skale-manager project to the SKALE contracts library""" from __future__ import annotations -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING from eth_utils.address import to_canonical_address from skale_contracts.instance import Instance, DEFAULT_GET_VERSION_FUNCTION @@ -9,7 +9,7 @@ if TYPE_CHECKING: - from eth_typing import Address + from eth_typing import Address, ChecksumAddress from web3.contract.contract import Contract SKALE_MANAGER_ABI = [ @@ -48,14 +48,11 @@ def __init__(self, project: Project, address: Address) -> None: 'TimeHelpersWithDebug': 'TimeHelpers' } - def get_contract_address(self, name: str) -> Address: + def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: return to_canonical_address( self.contract_manager.functions.getContract(self._actual_name(name)).call() ) - def _get_version(self) -> str: - return cast(str, self.skale_manager.functions.version().call()) - def _actual_name(self, name: str) -> str: if name in self.custom_names: return self.custom_names[name] From d36ac163f15c693ee670af7cb119a71f7ba2aeb1 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 2 Apr 2024 16:53:55 +0300 Subject: [PATCH 02/11] Add skale_allocator.py --- .../projects/skale_allocator.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 python/src/skale_contracts/projects/skale_allocator.py diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py new file mode 100644 index 0000000..6a76b85 --- /dev/null +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -0,0 +1,49 @@ +"""Module connects skale-manager project to the SKALE contracts library""" + +from __future__ import annotations +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 + + +if TYPE_CHECKING: + from eth_typing import Address, ChecksumAddress + + +class SkaleAllocatorInstance(Instance): + """Represents instance of skale-allocator""" + def __init__(self, project: Project, address: Address) -> None: + super().__init__(project, address) + self.allocator = self.get_contract("Allocator") + + def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: + if name == 'Allocator': + return self.address + if name == 'Escrow': + if len(args) > 0: + beneficiary = args[0] + if self.web3.is_address(beneficiary): + return self._get_escrow(to_canonical_address(beneficiary)) + raise ValueError('Beneficiary is not set') + raise ValueError(f'Contract ${name} is not found') + + def _get_escrow (self, beneficiary: Address) -> Address: + return to_canonical_address( + self.allocator.functions.getEscrowAddress(beneficiary).call() + ) + + +class SkaleAllocatorProject(Project): + """Represents skale-allocator project""" + + @property + def github_repo(self) -> str: + return 'https://github.com/skalenetwork/skale-allocator/' + + def create_instance(self, address: Address) -> Instance: + return SkaleAllocatorInstance(self, address) + + def get_abi_filename(self, version: str) -> str: + return f'skale-allocator-{version}-abi.json' From 09cb38c39e7b31355f962c80e915bd89b7c71ba8 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 2 Apr 2024 16:58:44 +0300 Subject: [PATCH 03/11] Fix typo --- python/src/skale_contracts/projects/skale_allocator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index 6a76b85..952a3e1 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -1,4 +1,4 @@ -"""Module connects skale-manager project to the SKALE contracts library""" +"""Module connects skale-allocator project to the SKALE contracts library""" from __future__ import annotations from typing import TYPE_CHECKING From c6397617db293dad921a9220a8159e4c23692bab Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 2 Apr 2024 18:28:25 +0300 Subject: [PATCH 04/11] Update project factory --- python/src/skale_contracts/project.py | 18 +++++++++--- python/src/skale_contracts/project_factory.py | 28 +++++++------------ .../src/skale_contracts/project_metadata.py | 4 --- python/src/skale_contracts/projects/ima.py | 12 ++++++-- .../projects/skale_allocator.py | 7 +++-- .../skale_contracts/projects/skale_manager.py | 7 +++-- 6 files changed, 41 insertions(+), 35 deletions(-) delete mode 100644 python/src/skale_contracts/project_metadata.py diff --git a/python/src/skale_contracts/project.py b/python/src/skale_contracts/project.py index 8be3bf7..5352cba 100644 --- a/python/src/skale_contracts/project.py +++ b/python/src/skale_contracts/project.py @@ -11,22 +11,32 @@ if TYPE_CHECKING: from eth_typing import Address from .network import Network - from .project_metadata import ProjectMetadata class Project(ABC): """Represents set of smart contracts known as project""" - def __init__(self, network: Network, metadata: ProjectMetadata) -> None: + def __init__(self, network: Network) -> None: super().__init__() self.network = network - self._metadata = metadata + + @staticmethod + @abstractmethod + def name() -> str: + """Name of the project""" @property @abstractmethod def github_repo(self) -> str: """URL of github repo with the project""" + + @property + def folder(self) -> str: + """Folder name with instances json files""" + return self.name() + + def get_instance(self, alias_or_address: str) -> Instance: """Create instance object based on alias or address""" if self.network.web3.is_address(alias_or_address): @@ -63,7 +73,7 @@ def get_instance_data_url(self, alias: str) -> str: """Get URL of a file containing address for provided alias""" if self.network.is_listed(): return f'{REPOSITORY_URL}{self.network.as_listed().path}/' + \ - f'{self._metadata.path}/{alias}.json' + f'{self.folder}/{alias}.json' raise ValueError('Network is unknown') @abstractmethod diff --git a/python/src/skale_contracts/project_factory.py b/python/src/skale_contracts/project_factory.py index 8626b0b..1446669 100644 --- a/python/src/skale_contracts/project_factory.py +++ b/python/src/skale_contracts/project_factory.py @@ -2,33 +2,25 @@ from __future__ import annotations from typing import TYPE_CHECKING -from attr import dataclass +import inspect +from .project import Project from . import projects -from .project_metadata import ProjectMetadata if TYPE_CHECKING: - from .project import Project from .network import Network -@dataclass -class Projects: - """Contains all known projects""" - skale_manager = ProjectMetadata(name='skale-manager', path='skale-manager') - mainnet_ima = ProjectMetadata(name='mainnet-ima', path='mainnet-ima') - schain_ima = ProjectMetadata(name='schain-ima', path='schain-ima') - skale_allocator = ProjectMetadata(name='skale-allocator', path='skale-allocator') +projects_dict = { + class_type.name(): class_type + for _, class_type + in inspect.getmembers(projects, inspect.isclass) + if issubclass(class_type, Project) +} def create_project(network: Network, name: str) -> Project: """Create Project object based on it's name""" - if name == Projects.skale_manager.name: - return projects.SkaleManager(network, Projects.skale_manager) - if name == Projects.mainnet_ima.name: - return projects.MainnetIma(network, Projects.mainnet_ima) - if name == Projects.schain_ima.name: - return projects.SchainIma(network, Projects.schain_ima) - if name == Projects.skale_allocator.name: - return projects.SkaleAllocator(network, Projects.skale_allocator) + if name in projects_dict: + return projects_dict[name](network) raise ValueError(f'Project with name {name} is unknown') diff --git a/python/src/skale_contracts/project_metadata.py b/python/src/skale_contracts/project_metadata.py deleted file mode 100644 index 96435a8..0000000 --- a/python/src/skale_contracts/project_metadata.py +++ /dev/null @@ -1,4 +0,0 @@ -"""Tools for project metadata processing""" -from collections import namedtuple - -ProjectMetadata = namedtuple('ProjectMetadata', ['name', 'path']) diff --git a/python/src/skale_contracts/projects/ima.py b/python/src/skale_contracts/projects/ima.py index cab97be..be4f89f 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -30,9 +30,7 @@ def __init__(self, project: Project, address: Address) -> None: class ImaProject(Project): """Represents IMA project""" - @property - def github_repo(self) -> str: - return 'https://github.com/skalenetwork/ima/' + github_repo = 'https://github.com/skalenetwork/ima/' class MainnetImaInstance(ImaInstance): @@ -74,6 +72,10 @@ def contract_manager(self) -> Contract: class MainnetImaProject(ImaProject): """Represents mainnet part of IMA project""" + @staticmethod + def name() -> str: + return 'mainnet-ima' + def create_instance(self, address: Address) -> Instance: return MainnetImaInstance(self, address) @@ -107,6 +109,10 @@ def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> class SchainImaProject(ImaProject): """Represents schain part of IMA project""" + @staticmethod + def name() -> str: + return 'schain-ima' + def get_instance(self, alias_or_address: str) -> Instance: if alias_or_address == PREDEPLOYED_ALIAS: return self.create_instance(SchainImaInstance.PREDEPLOYED['MessageProxyForSchain']) diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index 952a3e1..1075ac9 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -38,9 +38,10 @@ def _get_escrow (self, beneficiary: Address) -> Address: class SkaleAllocatorProject(Project): """Represents skale-allocator project""" - @property - def github_repo(self) -> str: - return 'https://github.com/skalenetwork/skale-allocator/' + @staticmethod + def name() -> str: + return 'skale-allocator' + github_repo = 'https://github.com/skalenetwork/skale-allocator/' def create_instance(self, address: Address) -> Instance: return SkaleAllocatorInstance(self, address) diff --git a/python/src/skale_contracts/projects/skale_manager.py b/python/src/skale_contracts/projects/skale_manager.py index 0733df8..b6737a5 100644 --- a/python/src/skale_contracts/projects/skale_manager.py +++ b/python/src/skale_contracts/projects/skale_manager.py @@ -62,9 +62,10 @@ def _actual_name(self, name: str) -> str: class SkaleManagerProject(Project): """Represents skale-manager project""" - @property - def github_repo(self) -> str: - return 'https://github.com/skalenetwork/skale-manager/' + @staticmethod + def name() -> str: + return 'skale-manager' + github_repo = 'https://github.com/skalenetwork/skale-manager/' def create_instance(self, address: Address) -> Instance: return SkaleManagerInstance(self, address) From 0f2bf6f72191f9655b3b41b0067ad593e1eb2157 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 2 Apr 2024 18:34:34 +0300 Subject: [PATCH 05/11] Rename variable --- python/src/skale_contracts/project_factory.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/src/skale_contracts/project_factory.py b/python/src/skale_contracts/project_factory.py index 1446669..be2cd21 100644 --- a/python/src/skale_contracts/project_factory.py +++ b/python/src/skale_contracts/project_factory.py @@ -12,10 +12,10 @@ projects_dict = { - class_type.name(): class_type - for _, class_type + project_type.name(): project_type + for _, project_type in inspect.getmembers(projects, inspect.isclass) - if issubclass(class_type, Project) + if issubclass(project_type, Project) } From c0e803987971277e6d02a4b81e91d8a8ff70a553 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 3 Apr 2024 18:01:42 +0300 Subject: [PATCH 06/11] Add a flake8 check --- python/scripts/full_check.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/scripts/full_check.sh b/python/scripts/full_check.sh index 391145b..efd36c6 100755 --- a/python/scripts/full_check.sh +++ b/python/scripts/full_check.sh @@ -10,3 +10,5 @@ echo "Run pylint" pylint src echo "Run mypy" mypy --strict src +echo "Run flake8" +flake8 src From 3fb731d38614c434ff98d2fa4a806376e375b5b8 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 3 Apr 2024 18:14:45 +0300 Subject: [PATCH 07/11] Remove long lines --- python/src/skale_contracts/instance.py | 16 ++++- python/src/skale_contracts/metadata.py | 5 +- python/src/skale_contracts/network.py | 13 +++- python/src/skale_contracts/project.py | 3 +- python/src/skale_contracts/projects/ima.py | 59 +++++++++++++------ .../projects/skale_allocator.py | 6 +- .../skale_contracts/projects/skale_manager.py | 36 ++++++++--- 7 files changed, 106 insertions(+), 32 deletions(-) diff --git a/python/src/skale_contracts/instance.py b/python/src/skale_contracts/instance.py index a3da474..c8d87da 100644 --- a/python/src/skale_contracts/instance.py +++ b/python/src/skale_contracts/instance.py @@ -80,14 +80,24 @@ def version(self) -> str: def abi(self) -> SkaleAbi: """Get abi file of the project instance""" if self._abi is None: - self._abi = json.loads(self._project.download_abi_file(self.version)) + self._abi = json.loads( + self._project.download_abi_file(self.version) + ) return self._abi @abstractmethod - def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: + def get_contract_address( + self, + name: str, + *args: str|Address|ChecksumAddress + ) -> Address: """Get address of the contract by it's name""" - def get_contract(self, name: str, *args: str|Address|ChecksumAddress) -> Contract: + def get_contract( + self, + name: str, + *args: str|Address|ChecksumAddress + ) -> Contract: """Get Contract object of the contract by it's name""" address = self.get_contract_address(name, *args) return self.web3.eth.contract(address=address, abi=self.abi[name]) diff --git a/python/src/skale_contracts/metadata.py b/python/src/skale_contracts/metadata.py index 924db1a..9e30c2b 100644 --- a/python/src/skale_contracts/metadata.py +++ b/python/src/skale_contracts/metadata.py @@ -49,7 +49,10 @@ def download(self) -> None: metadata = MetadataFile.from_json(metadata_response.text) self.networks = metadata.networks - def get_network_by_chain_id(self, chain_id: int) -> Optional[NetworkMetadata]: + def get_network_by_chain_id( + self, + chain_id: int + ) -> Optional[NetworkMetadata]: """Get network metadata by it's chain id. Returns None if there is no such network in the metadata. """ diff --git a/python/src/skale_contracts/network.py b/python/src/skale_contracts/network.py index 1603ca9..789658d 100644 --- a/python/src/skale_contracts/network.py +++ b/python/src/skale_contracts/network.py @@ -15,7 +15,11 @@ class Network: """Represents blockchain with deployed smart contracts projects""" - def __init__(self, skale_contracts: SkaleContracts, provider: BaseProvider): + def __init__( + self, + skale_contracts: SkaleContracts, + provider: BaseProvider + ): self.web3 = Web3(provider) self._skale_contracts = skale_contracts @@ -39,7 +43,12 @@ def as_listed(self) -> ListedNetwork: class ListedNetwork(Network): """Network that is listed in the metadata""" - def __init__(self, skale_contracts: SkaleContracts, provider: BaseProvider, path: str): + def __init__( + self, + skale_contracts: SkaleContracts, + provider: BaseProvider, + path: str + ): super().__init__(skale_contracts, provider) self.path = path diff --git a/python/src/skale_contracts/project.py b/python/src/skale_contracts/project.py index 5352cba..31d7154 100644 --- a/python/src/skale_contracts/project.py +++ b/python/src/skale_contracts/project.py @@ -63,7 +63,8 @@ def download_abi_file(self, version: str) -> str: def get_abi_url(self, version: str) -> str: """Calculate URL of ABI file""" - return f'{self.github_repo}releases/download/{version}/{self.get_abi_filename(version)}' + filename = self.get_abi_filename(version) + return f'{self.github_repo}releases/download/{version}/{filename}' @abstractmethod 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 be4f89f..7439196 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -24,7 +24,10 @@ class ImaInstance(Instance): """Represents instance of IMA""" def __init__(self, project: Project, address: Address) -> None: super().__init__(project, address) - self.message_proxy = self.web3.eth.contract(address=address, abi=MESSAGE_PROXY_ABI) + self.message_proxy = self.web3.eth.contract( + address=address, + abi=MESSAGE_PROXY_ABI + ) class ImaProject(Project): @@ -40,16 +43,21 @@ def __init__(self, project: Project, address: Address) -> None: super().__init__(project, address) self._contract_manager: Contract | None = None - def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: + def get_contract_address( + self, + name: str, *args: str|Address|ChecksumAddress + ) -> Address: if name == 'MessageProxyForMainnet': return self.address if name == 'CommunityPool': return to_canonical_address( - self.get_contract("MessageProxyForMainnet").functions.communityPool().call() + self.get_contract("MessageProxyForMainnet")\ + .functions.communityPool().call() ) if name == 'Linker': return to_canonical_address( - self.get_contract("MessageProxyForMainnet").functions.linker().call() + self.get_contract("MessageProxyForMainnet")\ + .functions.linker().call() ) return to_canonical_address( self.contract_manager.functions.getContract(name).call() @@ -57,7 +65,8 @@ def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> @property def contract_manager(self) -> Contract: - """ContractManager contract of a skale-manager instance associated with the IMA""" + """ContractManager contract of a skale-manager instance +associated with the IMA""" if self._contract_manager is None: self._contract_manager = self.web3.eth.contract( address=to_canonical_address( @@ -88,19 +97,33 @@ class SchainImaInstance(ImaInstance): PREDEPLOYED: dict[str, Address] = { name: to_canonical_address(address) for name, address in { - 'ProxyAdmin': '0xd2aAa00000000000000000000000000000000000', - 'MessageProxyForSchain': '0xd2AAa00100000000000000000000000000000000', - 'KeyStorage': '0xd2aaa00200000000000000000000000000000000', - 'CommunityLocker': '0xD2aaa00300000000000000000000000000000000', - 'TokenManagerEth': '0xd2AaA00400000000000000000000000000000000', - 'TokenManagerERC20': '0xD2aAA00500000000000000000000000000000000', - 'TokenManagerERC721': '0xD2aaa00600000000000000000000000000000000', - 'TokenManagerLinker': '0xD2aAA00800000000000000000000000000000000', - 'TokenManagerERC1155': '0xD2aaA00900000000000000000000000000000000', - 'TokenManagerERC721WithMetadata': '0xd2AaA00a00000000000000000000000000000000' + 'ProxyAdmin': + '0xd2aAa00000000000000000000000000000000000', + 'MessageProxyForSchain': + '0xd2AAa00100000000000000000000000000000000', + 'KeyStorage': + '0xd2aaa00200000000000000000000000000000000', + 'CommunityLocker': + '0xD2aaa00300000000000000000000000000000000', + 'TokenManagerEth': + '0xd2AaA00400000000000000000000000000000000', + 'TokenManagerERC20': + '0xD2aAA00500000000000000000000000000000000', + 'TokenManagerERC721': + '0xD2aaa00600000000000000000000000000000000', + 'TokenManagerLinker': + '0xD2aAA00800000000000000000000000000000000', + 'TokenManagerERC1155': + '0xD2aaA00900000000000000000000000000000000', + 'TokenManagerERC721WithMetadata': + '0xd2AaA00a00000000000000000000000000000000' }.items()} - def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: + def get_contract_address( + self, + name: str, + *args: str|Address|ChecksumAddress + ) -> Address: if name in self.PREDEPLOYED: return self.PREDEPLOYED[name] raise RuntimeError(f"Can't get address of {name} contract") @@ -115,7 +138,9 @@ def name() -> str: def get_instance(self, alias_or_address: str) -> Instance: if alias_or_address == PREDEPLOYED_ALIAS: - return self.create_instance(SchainImaInstance.PREDEPLOYED['MessageProxyForSchain']) + return self.create_instance( + SchainImaInstance.PREDEPLOYED['MessageProxyForSchain'] + ) return super().get_instance(alias_or_address) def create_instance(self, address: Address) -> Instance: diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index 1075ac9..ca7e1ac 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -18,7 +18,11 @@ def __init__(self, project: Project, address: Address) -> None: super().__init__(project, address) self.allocator = self.get_contract("Allocator") - def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: + def get_contract_address( + self, + name: str, + *args: str|Address|ChecksumAddress + ) -> Address: if name == 'Allocator': return self.address if name == 'Escrow': diff --git a/python/src/skale_contracts/projects/skale_manager.py b/python/src/skale_contracts/projects/skale_manager.py index b6737a5..e3e42a9 100644 --- a/python/src/skale_contracts/projects/skale_manager.py +++ b/python/src/skale_contracts/projects/skale_manager.py @@ -16,7 +16,11 @@ { "inputs": [], "name": "contractManager", - "outputs": [{ "internalType": "contract IContractManager", "name": "", "type": "address" }], + "outputs": [{ + "internalType": "contract IContractManager", + "name": "", + "type": "address" + }], "stateMutability": "view", "type": "function" }, DEFAULT_GET_VERSION_FUNCTION @@ -24,9 +28,17 @@ CONTRACT_MANAGER_ABI = [ { - "inputs": [{ "internalType": "string", "name": "name", "type": "string" }], + "inputs": [{ + "internalType": "string", + "name": "name", + "type": "string" + }], "name": "getContract", - "outputs": [{ "internalType": "address", "name": "contractAddress", "type": "address" }], + "outputs": [{ + "internalType": "address", + "name": "contractAddress", + "type": "address" + }], "stateMutability": "view", "type": "function" } @@ -37,8 +49,12 @@ class SkaleManagerInstance(Instance): """Represents instance of skale-manager""" def __init__(self, project: Project, address: Address) -> None: super().__init__(project, address) - self.skale_manager = self.web3.eth.contract(address=address, abi=SKALE_MANAGER_ABI) - contract_manager_address: Address = self.skale_manager.functions.contractManager().call() + self.skale_manager = self.web3.eth.contract( + address=address, + abi=SKALE_MANAGER_ABI + ) + contract_manager_address: Address = \ + self.skale_manager.functions.contractManager().call() self.contract_manager: Contract = self.web3.eth.contract( address=contract_manager_address, abi=CONTRACT_MANAGER_ABI @@ -48,9 +64,15 @@ def __init__(self, project: Project, address: Address) -> None: 'TimeHelpersWithDebug': 'TimeHelpers' } - def get_contract_address(self, name: str, *args: str|Address|ChecksumAddress) -> Address: + def get_contract_address( + self, + name: str, + *args: str|Address|ChecksumAddress + ) -> Address: return to_canonical_address( - self.contract_manager.functions.getContract(self._actual_name(name)).call() + self.contract_manager.functions.getContract( + self._actual_name(name) + ).call() ) def _actual_name(self, name: str) -> str: From b9242ea09fb457f4395b68c7b6bc89569c971caf Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 3 Apr 2024 18:16:43 +0300 Subject: [PATCH 08/11] Add missing whitespaces --- python/src/skale_contracts/instance.py | 4 ++-- python/src/skale_contracts/projects/ima.py | 4 ++-- python/src/skale_contracts/projects/skale_allocator.py | 2 +- python/src/skale_contracts/projects/skale_manager.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/src/skale_contracts/instance.py b/python/src/skale_contracts/instance.py index c8d87da..90d8a72 100644 --- a/python/src/skale_contracts/instance.py +++ b/python/src/skale_contracts/instance.py @@ -89,14 +89,14 @@ def abi(self) -> SkaleAbi: def get_contract_address( self, name: str, - *args: str|Address|ChecksumAddress + *args: str | Address | ChecksumAddress ) -> Address: """Get address of the contract by it's name""" def get_contract( self, name: str, - *args: str|Address|ChecksumAddress + *args: str | Address | ChecksumAddress ) -> Contract: """Get Contract object of the contract by it's name""" address = self.get_contract_address(name, *args) diff --git a/python/src/skale_contracts/projects/ima.py b/python/src/skale_contracts/projects/ima.py index 7439196..ce5b587 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -45,7 +45,7 @@ def __init__(self, project: Project, address: Address) -> None: def get_contract_address( self, - name: str, *args: str|Address|ChecksumAddress + name: str, *args: str | Address | ChecksumAddress ) -> Address: if name == 'MessageProxyForMainnet': return self.address @@ -122,7 +122,7 @@ class SchainImaInstance(ImaInstance): def get_contract_address( self, name: str, - *args: str|Address|ChecksumAddress + *args: str | Address | ChecksumAddress ) -> Address: if name in self.PREDEPLOYED: return self.PREDEPLOYED[name] diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index ca7e1ac..567bb25 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -21,7 +21,7 @@ def __init__(self, project: Project, address: Address) -> None: def get_contract_address( self, name: str, - *args: str|Address|ChecksumAddress + *args: str | Address | ChecksumAddress ) -> Address: if name == 'Allocator': return self.address diff --git a/python/src/skale_contracts/projects/skale_manager.py b/python/src/skale_contracts/projects/skale_manager.py index e3e42a9..5d5fe90 100644 --- a/python/src/skale_contracts/projects/skale_manager.py +++ b/python/src/skale_contracts/projects/skale_manager.py @@ -67,7 +67,7 @@ def __init__(self, project: Project, address: Address) -> None: def get_contract_address( self, name: str, - *args: str|Address|ChecksumAddress + *args: str | Address | ChecksumAddress ) -> Address: return to_canonical_address( self.contract_manager.functions.getContract( From 89fbb7b3c3a424f243e08c85cb9e151397293e28 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 3 Apr 2024 18:17:50 +0300 Subject: [PATCH 09/11] Remove redundant backslashes --- python/src/skale_contracts/projects/ima.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/skale_contracts/projects/ima.py b/python/src/skale_contracts/projects/ima.py index ce5b587..d67ccbf 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -51,12 +51,12 @@ def get_contract_address( return self.address if name == 'CommunityPool': return to_canonical_address( - self.get_contract("MessageProxyForMainnet")\ + self.get_contract("MessageProxyForMainnet") .functions.communityPool().call() ) if name == 'Linker': return to_canonical_address( - self.get_contract("MessageProxyForMainnet")\ + self.get_contract("MessageProxyForMainnet") .functions.linker().call() ) return to_canonical_address( From 0593a0dd5d1c1f8c361dc2467fec200e17f9ad77 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 3 Apr 2024 18:20:35 +0300 Subject: [PATCH 10/11] Fix whitespaces --- python/src/skale_contracts/instance.py | 3 ++- python/src/skale_contracts/metadata.py | 2 ++ python/src/skale_contracts/project.py | 2 -- python/src/skale_contracts/project_factory.py | 4 ++-- python/src/skale_contracts/projects/skale_allocator.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/python/src/skale_contracts/instance.py b/python/src/skale_contracts/instance.py index 90d8a72..19b9b9a 100644 --- a/python/src/skale_contracts/instance.py +++ b/python/src/skale_contracts/instance.py @@ -25,7 +25,7 @@ "stateMutability": "view", "payable": False, "inputs": [], - "outputs": [ { "type": "string", "name": "" } ] + "outputs": [{"type": "string", "name": ""}] } @@ -33,6 +33,7 @@ class InstanceData: """Contains instance data""" data: dict[str, str] + @classmethod def from_json(cls, data: str) -> InstanceData: """Create InstanceData object from json string""" diff --git a/python/src/skale_contracts/metadata.py b/python/src/skale_contracts/metadata.py index 9e30c2b..c4a1287 100644 --- a/python/src/skale_contracts/metadata.py +++ b/python/src/skale_contracts/metadata.py @@ -16,6 +16,7 @@ class NetworkMetadata: chain_id: int path: str + @dataclass class MetadataFile: """Represents file with metadata""" @@ -33,6 +34,7 @@ def from_json(cls, data: str) -> MetadataFile: path=network['path'])) return cls(networks) + class Metadata: """Class to manage SKALE contracts metadata""" networks: list[NetworkMetadata] diff --git a/python/src/skale_contracts/project.py b/python/src/skale_contracts/project.py index 31d7154..59599ef 100644 --- a/python/src/skale_contracts/project.py +++ b/python/src/skale_contracts/project.py @@ -30,13 +30,11 @@ def name() -> str: def github_repo(self) -> str: """URL of github repo with the project""" - @property def folder(self) -> str: """Folder name with instances json files""" return self.name() - def get_instance(self, alias_or_address: str) -> Instance: """Create instance object based on alias or address""" if self.network.web3.is_address(alias_or_address): diff --git a/python/src/skale_contracts/project_factory.py b/python/src/skale_contracts/project_factory.py index be2cd21..035b846 100644 --- a/python/src/skale_contracts/project_factory.py +++ b/python/src/skale_contracts/project_factory.py @@ -14,8 +14,8 @@ projects_dict = { project_type.name(): project_type for _, project_type - in inspect.getmembers(projects, inspect.isclass) - if issubclass(project_type, Project) + in inspect.getmembers(projects, inspect.isclass) + if issubclass(project_type, Project) } diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index 567bb25..0c3cb5c 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -33,7 +33,7 @@ def get_contract_address( raise ValueError('Beneficiary is not set') raise ValueError(f'Contract ${name} is not found') - def _get_escrow (self, beneficiary: Address) -> Address: + def _get_escrow(self, beneficiary: Address) -> Address: return to_canonical_address( self.allocator.functions.getEscrowAddress(beneficiary).call() ) From 691331ebf9fef1e21603f3f5799ff4ccf73fc933 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 4 Apr 2024 18:16:37 +0300 Subject: [PATCH 11/11] Replace static method with instance one --- python/src/skale_contracts/projects/ima.py | 4 +++- python/src/skale_contracts/projects/skale_allocator.py | 5 ++++- python/src/skale_contracts/projects/skale_manager.py | 5 ++++- python/test/requirements.txt | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/python/src/skale_contracts/projects/ima.py b/python/src/skale_contracts/projects/ima.py index d67ccbf..dd2a0d7 100644 --- a/python/src/skale_contracts/projects/ima.py +++ b/python/src/skale_contracts/projects/ima.py @@ -33,7 +33,9 @@ def __init__(self, project: Project, address: Address) -> None: class ImaProject(Project): """Represents IMA project""" - github_repo = 'https://github.com/skalenetwork/ima/' + @property + def github_repo(self) -> str: + return 'https://github.com/skalenetwork/ima/' class MainnetImaInstance(ImaInstance): diff --git a/python/src/skale_contracts/projects/skale_allocator.py b/python/src/skale_contracts/projects/skale_allocator.py index 0c3cb5c..dcc1350 100644 --- a/python/src/skale_contracts/projects/skale_allocator.py +++ b/python/src/skale_contracts/projects/skale_allocator.py @@ -45,7 +45,10 @@ class SkaleAllocatorProject(Project): @staticmethod def name() -> str: return 'skale-allocator' - github_repo = 'https://github.com/skalenetwork/skale-allocator/' + + @property + def github_repo(self) -> str: + return 'https://github.com/skalenetwork/skale-allocator/' def create_instance(self, address: Address) -> Instance: return SkaleAllocatorInstance(self, address) diff --git a/python/src/skale_contracts/projects/skale_manager.py b/python/src/skale_contracts/projects/skale_manager.py index 5d5fe90..1068e85 100644 --- a/python/src/skale_contracts/projects/skale_manager.py +++ b/python/src/skale_contracts/projects/skale_manager.py @@ -87,7 +87,10 @@ class SkaleManagerProject(Project): @staticmethod def name() -> str: return 'skale-manager' - github_repo = 'https://github.com/skalenetwork/skale-manager/' + + @property + def github_repo(self) -> str: + return 'https://github.com/skalenetwork/skale-manager/' def create_instance(self, address: Address) -> Instance: return SkaleManagerInstance(self, address) diff --git a/python/test/requirements.txt b/python/test/requirements.txt index ec45407..29b2fa0 100644 --- a/python/test/requirements.txt +++ b/python/test/requirements.txt @@ -1,3 +1,4 @@ +flake8 mypy pylint types-requests