From b9209d6531c0a90975c146e1126ebbbad4204915 Mon Sep 17 00:00:00 2001 From: cyc60 Date: Wed, 29 Apr 2026 13:06:58 +0300 Subject: [PATCH 1/2] Add contract release checker --- pyproject.toml | 2 +- sw_utils/__init__.py | 5 +++ sw_utils/networks.py | 75 ++++++++++++++++++++++++++++++++++++++++++++ sw_utils/pectra.py | 17 ---------- sw_utils/release.py | 55 ++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 18 deletions(-) delete mode 100644 sw_utils/pectra.py create mode 100644 sw_utils/release.py diff --git a/pyproject.toml b/pyproject.toml index 0823c94..37e33bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "sw-utils" -version = "v0.12.15" +version = "v0.12.16" description = "StakeWise Python utils" authors = ["StakeWise Labs "] license = "GPL-3.0-or-later" diff --git a/sw_utils/__init__.py b/sw_utils/__init__.py index 069c7b6..5894f07 100644 --- a/sw_utils/__init__.py +++ b/sw_utils/__init__.py @@ -33,6 +33,11 @@ from .os_token_converter import OsTokenConverter from .password import generate_password from .protocol_config import build_protocol_config +from .release import ( + is_meta_vault_upgraded_to_release, + is_vault_upgraded_to_pectra, + is_vault_upgraded_to_release, +) from .signing import ( DepositData, DepositMessage, diff --git a/sw_utils/networks.py b/sw_utils/networks.py index e3a1c68..e663510 100644 --- a/sw_utils/networks.py +++ b/sw_utils/networks.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from enum import IntEnum from eth_typing import BlockNumber, ChecksumAddress, HexAddress, HexStr from web3 import Web3 @@ -16,6 +17,23 @@ EMPTY_ADDR_HEX = HexAddress(HexStr('0x' + '00' * 20)) +class ContractReleaseVersion(IntEnum): + V4 = 4 # Pectra release + V5 = 5 # Added redemptions, added sub-vaults registry for meta vaults + + +# Add alias for readability +PECTRA_CONTRACTS_RELEASE_VERSION = ContractReleaseVersion.V4 + + +@dataclass +class ContractRelease: + version: ContractReleaseVersion + vault_version: int + genesis_vault_version: int + meta_vault_version: int + + @dataclass # pylint: disable-next=too-many-instance-attributes class BaseNetworkConfig: @@ -55,6 +73,7 @@ class BaseNetworkConfig: NODES_MANAGER_GENESIS_BLOCK: BlockNumber OS_TOKEN_REDEEMER_CONTRACT_ADDRESS: ChecksumAddress VALIDATORS_CHECKER_CONTRACT_ADDRESS: ChecksumAddress + CONTRACTS_RELEASES: list[ContractRelease] @property def SECONDS_PER_BLOCK(self) -> int: @@ -79,6 +98,20 @@ def SHAPELLA_FORK(self) -> ConsensusFork: def PECTRA_SLOT(self) -> int: return self.PECTRA_EPOCH * self.SLOTS_PER_EPOCH + @property + def CONTRACTS_RELEASE_VERSION_TO_RELEASE(self) -> dict[ContractReleaseVersion, ContractRelease]: + return {release.version: release for release in self.CONTRACTS_RELEASES} + + @property + def CONTRACTS_RELEASE_V4(self) -> ContractRelease: + """Pectra release""" + return self.CONTRACTS_RELEASE_VERSION_TO_RELEASE[ContractReleaseVersion.V4] + + @property + def CONTRACTS_RELEASE_V5(self) -> ContractRelease: + """Added redemptions, added sub-vaults registry for meta vaults""" + return self.CONTRACTS_RELEASE_VERSION_TO_RELEASE[ContractReleaseVersion.V5] + NETWORKS = { MAINNET: BaseNetworkConfig( @@ -146,6 +179,20 @@ def PECTRA_SLOT(self) -> int: VALIDATORS_CHECKER_CONTRACT_ADDRESS=Web3.to_checksum_address( '0x508e82B5119CCfB923C387d62D2Ae7B56Df79906' ), + CONTRACTS_RELEASES=[ + ContractRelease( + version=ContractReleaseVersion.V4, + vault_version=5, + genesis_vault_version=5, + meta_vault_version=5, + ), + ContractRelease( + version=ContractReleaseVersion.V5, + vault_version=5, + genesis_vault_version=5, + meta_vault_version=6, + ), + ], ), HOODI: BaseNetworkConfig( SLOTS_PER_EPOCH=32, @@ -210,6 +257,20 @@ def PECTRA_SLOT(self) -> int: VALIDATORS_CHECKER_CONTRACT_ADDRESS=Web3.to_checksum_address( '0xF1b78B96212DCcbf8F34A83535e58864311Fb9eB' ), + CONTRACTS_RELEASES=[ + ContractRelease( + version=ContractReleaseVersion.V4, + vault_version=5, + genesis_vault_version=5, + meta_vault_version=5, + ), + ContractRelease( + version=ContractReleaseVersion.V5, + vault_version=5, + genesis_vault_version=5, + meta_vault_version=6, + ), + ], ), GNOSIS: BaseNetworkConfig( SLOTS_PER_EPOCH=16, @@ -274,6 +335,20 @@ def PECTRA_SLOT(self) -> int: VALIDATORS_CHECKER_CONTRACT_ADDRESS=Web3.to_checksum_address( '0x80353898B72417AC5701a9809A9eF63F691BdE86' ), + CONTRACTS_RELEASES=[ + ContractRelease( + version=ContractReleaseVersion.V4, + vault_version=3, + genesis_vault_version=4, + meta_vault_version=3, + ), + ContractRelease( + version=ContractReleaseVersion.V5, + vault_version=3, + genesis_vault_version=4, + meta_vault_version=4, + ), + ], ), } diff --git a/sw_utils/pectra.py b/sw_utils/pectra.py deleted file mode 100644 index 8172097..0000000 --- a/sw_utils/pectra.py +++ /dev/null @@ -1,17 +0,0 @@ -from eth_typing import ChecksumAddress - -from sw_utils.networks import GNO_NETWORKS, NETWORKS - -GNO_GENESIS_VAULT_PECTRA_VERSION = 4 - - -def get_pectra_vault_version(network: str, vault_address: ChecksumAddress) -> int: - """ - Returns the minimal vault version which supports Pectra fork. - """ - network_config = NETWORKS[network] - - if network in GNO_NETWORKS and vault_address == network_config.GENESIS_VAULT_CONTRACT_ADDRESS: - return GNO_GENESIS_VAULT_PECTRA_VERSION - - return network_config.PECTRA_VAULT_VERSION diff --git a/sw_utils/release.py b/sw_utils/release.py new file mode 100644 index 0000000..ba6e8d3 --- /dev/null +++ b/sw_utils/release.py @@ -0,0 +1,55 @@ +from eth_typing import ChecksumAddress + +from sw_utils.networks import ( + NETWORKS, + PECTRA_CONTRACTS_RELEASE_VERSION, + ContractReleaseVersion, +) + + +def is_vault_upgraded_to_pectra( + network: str, vault_address: ChecksumAddress, vault_version: int +) -> bool: + # Up to Pectra release, meta vault version is the same as regular vault version, + # so we can use the same function for both meta and non-meta vaults + return is_vault_upgraded_to_release( + network=network, + vault_address=vault_address, + vault_version=vault_version, + release_version=PECTRA_CONTRACTS_RELEASE_VERSION, + ) + + +def is_meta_vault_upgraded_to_release( + network: str, + vault_address: ChecksumAddress, + vault_version: int, + release_version: ContractReleaseVersion, +) -> bool: + return is_vault_upgraded_to_release( + network=network, + vault_address=vault_address, + vault_version=vault_version, + release_version=release_version, + is_meta_vault=True, + ) + + +def is_vault_upgraded_to_release( + network: str, + vault_address: ChecksumAddress, + vault_version: int, + release_version: ContractReleaseVersion, + is_meta_vault: bool = False, +) -> bool: + network_config = NETWORKS[network] + + release = network_config.CONTRACTS_RELEASE_VERSION_TO_RELEASE[release_version] + is_genesis_vault = vault_address == network_config.GENESIS_VAULT_CONTRACT_ADDRESS + if is_meta_vault: + min_version = release.meta_vault_version + elif is_genesis_vault: + min_version = release.genesis_vault_version + else: + min_version = release.vault_version + return vault_version >= min_version From c26210c8dc5c025219e6e4c973786c527b2a0b4a Mon Sep 17 00:00:00 2001 From: cyc60 Date: Wed, 29 Apr 2026 14:30:03 +0300 Subject: [PATCH 2/2] Version bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 37e33bc..e671c68 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "sw-utils" -version = "v0.12.16" +version = "v0.13.0" description = "StakeWise Python utils" authors = ["StakeWise Labs "] license = "GPL-3.0-or-later"