diff --git a/Makefile b/Makefile index 4b68d11c90..997ee84719 100644 --- a/Makefile +++ b/Makefile @@ -45,4 +45,4 @@ gha-docker: docker run -v $(PWD):/build -w /build --rm -i ${CONTAINER_NAME}:latest bash -c "make gha" storage-report: - bash "bin/storage-report.sh" "docs/storage-report/" + bash "bin/storage-report.sh" "docs/storage-report/" \ No newline at end of file diff --git a/script/configs/devnet/deploy_from_scratch.anvil.config.json b/script/configs/devnet/deploy_from_scratch.anvil.config.json index 96df127e1f..6d8b5fef76 100644 --- a/script/configs/devnet/deploy_from_scratch.anvil.config.json +++ b/script/configs/devnet/deploy_from_scratch.anvil.config.json @@ -51,5 +51,6 @@ "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 }, - "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", + "semver": "v1.0.3" } \ No newline at end of file diff --git a/script/configs/devnet/deploy_from_scratch.holesky.config.json b/script/configs/devnet/deploy_from_scratch.holesky.config.json index 3dc1f204d5..054a432868 100644 --- a/script/configs/devnet/deploy_from_scratch.holesky.config.json +++ b/script/configs/devnet/deploy_from_scratch.holesky.config.json @@ -51,5 +51,6 @@ "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 }, - "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" -} \ No newline at end of file + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", + "semver": "v0.0.0" +} diff --git a/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json b/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json index bcd808f715..99d3c54cbe 100644 --- a/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json +++ b/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json @@ -43,5 +43,6 @@ "DEALLOCATION_DELAY": 86400, "ALLOCATION_CONFIGURATION_DELAY": 600 }, - "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242" + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", + "semver": "v0.0.0" } \ No newline at end of file diff --git a/script/configs/local/deploy_from_scratch.anvil.config.json b/script/configs/local/deploy_from_scratch.anvil.config.json index f8b15599d4..3b516c4547 100644 --- a/script/configs/local/deploy_from_scratch.anvil.config.json +++ b/script/configs/local/deploy_from_scratch.anvil.config.json @@ -57,5 +57,6 @@ "DEALLOCATION_DELAY": 900, "ALLOCATION_CONFIGURATION_DELAY": 1200 }, - "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", + "semver": "v0.0.0" } \ No newline at end of file diff --git a/script/configs/local/deploy_from_scratch.slashing.anvil.config.json b/script/configs/local/deploy_from_scratch.slashing.anvil.config.json index 313bd1827a..af310692d5 100644 --- a/script/configs/local/deploy_from_scratch.slashing.anvil.config.json +++ b/script/configs/local/deploy_from_scratch.slashing.anvil.config.json @@ -57,5 +57,6 @@ "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 }, - "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", + "semver": "v0.0.0" } \ No newline at end of file diff --git a/script/configs/mainnet/mainnet-addresses.config.json b/script/configs/mainnet/mainnet-addresses.config.json index f47b5d9497..c33d7e8380 100644 --- a/script/configs/mainnet/mainnet-addresses.config.json +++ b/script/configs/mainnet/mainnet-addresses.config.json @@ -75,6 +75,7 @@ "executorMultisig": "0x369e6F597e22EaB55fFb173C6d9cD234BD699111", "operationsMultisig": "0xBE1685C81aA44FF9FB319dD389addd9374383e90", "pauserMultisig": "0x5050389572f2d220ad927CcbeA0D406831012390", - "timelock": "0xA6Db1A8C5a981d1536266D2a393c5F8dDb210EAF" + "timelock": "0xA6Db1A8C5a981d1536266D2a393c5F8dDb210EAF", + "semver": "v0.5.4" } } \ No newline at end of file diff --git a/script/deploy/devnet/deploy_from_scratch.s.sol b/script/deploy/devnet/deploy_from_scratch.s.sol index 5c2f888f55..dd07a6e0aa 100644 --- a/script/deploy/devnet/deploy_from_scratch.s.sol +++ b/script/deploy/devnet/deploy_from_scratch.s.sol @@ -76,6 +76,8 @@ contract DeployFromScratch is Script, Test { // strategies deployed StrategyBaseTVLLimits[] public deployedStrategyArray; + string SEMVER; + // IMMUTABLES TO SET uint64 GOERLI_GENESIS_TIME = 1616508000; @@ -121,6 +123,8 @@ contract DeployFromScratch is Script, Test { string memory config_data = vm.readFile(deployConfigPath); // bytes memory parsedData = vm.parseJson(config_data); + SEMVER = stdJson.readString(config_data, ".semver"); + STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".strategyManager.init_paused_status"); DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".delegation.init_paused_status"); DELEGATION_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint(config_data, ".delegation.init_withdrawal_delay_blocks"); @@ -227,37 +231,58 @@ contract DeployFromScratch is Script, Test { eigenPodImplementation = new EigenPod( ethPOSDeposit, eigenPodManager, - GOERLI_GENESIS_TIME + GOERLI_GENESIS_TIME, + SEMVER ); eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationImplementation = new DelegationManager(strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); - strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg); - avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg); + delegationImplementation = new DelegationManager( + strategyManager, + eigenPodManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + MIN_WITHDRAWAL_DELAY, + SEMVER + ); + + strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg, SEMVER); + avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg, SEMVER); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, delegation, - eigenLayerPauserReg + eigenLayerPauserReg, + SEMVER ); rewardsCoordinatorImplementation = new RewardsCoordinator( - delegation, - strategyManager, - allocationManager, - eigenLayerPauserReg, - permissionController, - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, - REWARDS_COORDINATOR_MAX_REWARDS_DURATION, - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams( + delegation, + strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, + REWARDS_COORDINATOR_MAX_REWARDS_DURATION, + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP, + SEMVER + ) + ); + allocationManagerImplementation = new AllocationManager( + delegation, + eigenLayerPauserReg, + permissionController, + DEALLOCATION_DELAY, + ALLOCATION_CONFIGURATION_DELAY, + SEMVER ); - allocationManagerImplementation = new AllocationManager(delegation, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); - permissionControllerImplementation = new PermissionController(); - strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg); + permissionControllerImplementation = new PermissionController(SEMVER); + strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg, SEMVER); // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. { @@ -325,7 +350,7 @@ contract DeployFromScratch is Script, Test { // Deploy strategyFactory & base // Create base strategy implementation - baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg); + baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg, SEMVER); // Create a proxy beacon for base strategy implementation strategyBeacon = new UpgradeableBeacon(address(baseStrategyImplementation)); diff --git a/script/deploy/local/Deploy_From_Scratch.s.sol b/script/deploy/local/Deploy_From_Scratch.s.sol index 8987c680e4..6201cd55a4 100644 --- a/script/deploy/local/Deploy_From_Scratch.s.sol +++ b/script/deploy/local/Deploy_From_Scratch.s.sol @@ -79,6 +79,8 @@ contract DeployFromScratch is Script, Test { // strategies deployed StrategyBaseTVLLimits[] public deployedStrategyArray; + string SEMVER; + // IMMUTABLES TO SET uint64 GOERLI_GENESIS_TIME = 1616508000; @@ -124,6 +126,8 @@ contract DeployFromScratch is Script, Test { string memory config_data = vm.readFile(deployConfigPath); // bytes memory parsedData = vm.parseJson(config_data); + SEMVER = stdJson.readString(config_data, ".semver"); + STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".strategyManager.init_paused_status"); DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".delegation.init_paused_status"); DELEGATION_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint(config_data, ".delegation.init_withdrawal_delay_blocks"); @@ -240,35 +244,54 @@ contract DeployFromScratch is Script, Test { } else { ethPOSDeposit = IETHPOSDeposit(stdJson.readAddress(config_data, ".ethPOSDepositAddress")); } - eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, GOERLI_GENESIS_TIME); + eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, GOERLI_GENESIS_TIME, SEMVER); eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationImplementation = new DelegationManager(strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); - strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg); - avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg); + delegationImplementation = new DelegationManager( + strategyManager, + eigenPodManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + MIN_WITHDRAWAL_DELAY, + SEMVER + ); + strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg, SEMVER); + avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg, SEMVER); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, delegation, - eigenLayerPauserReg + eigenLayerPauserReg, + SEMVER ); rewardsCoordinatorImplementation = new RewardsCoordinator( - delegation, - strategyManager, - allocationManager, - eigenLayerPauserReg, - permissionController, - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, - REWARDS_COORDINATOR_MAX_REWARDS_DURATION, - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams( + delegation, + strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, + REWARDS_COORDINATOR_MAX_REWARDS_DURATION, + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP, + SEMVER + ) + ); + allocationManagerImplementation = new AllocationManager( + delegation, + eigenLayerPauserReg, + permissionController, + DEALLOCATION_DELAY, + ALLOCATION_CONFIGURATION_DELAY, + SEMVER ); - allocationManagerImplementation = new AllocationManager(delegation, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); - permissionControllerImplementation = new PermissionController(); + permissionControllerImplementation = new PermissionController(SEMVER); // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. { @@ -340,7 +363,7 @@ contract DeployFromScratch is Script, Test { ); // deploy StrategyBaseTVLLimits contract implementation - baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg); + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg, SEMVER); // create upgradeable proxies that each point to the implementation and initialize them for (uint256 i = 0; i < strategyConfigs.length; ++i) { if (strategyConfigs[i].tokenAddress == address(0)) { diff --git a/script/deploy/local/deploy_from_scratch.slashing.s.sol b/script/deploy/local/deploy_from_scratch.slashing.s.sol index 38ba01b7de..bf07af1d0a 100644 --- a/script/deploy/local/deploy_from_scratch.slashing.s.sol +++ b/script/deploy/local/deploy_from_scratch.slashing.s.sol @@ -73,6 +73,8 @@ contract DeployFromScratch is Script, Test { address operationsMultisig; address pauserMultisig; + string SEMVER; + // the ETH2 deposit contract -- if not on mainnet, we deploy a mock as stand-in IETHPOSDeposit public ethPOSDeposit; @@ -124,6 +126,8 @@ contract DeployFromScratch is Script, Test { string memory config_data = vm.readFile(deployConfigPath); // bytes memory parsedData = vm.parseJson(config_data); + SEMVER = stdJson.readString(config_data, ".semver"); + MIN_WITHDRAWAL_DELAY = uint32(stdJson.readUint(config_data, ".delegation.withdrawal_delay_blocks")); STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".strategyManager.init_paused_status"); DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".delegation.init_paused_status"); @@ -234,36 +238,56 @@ contract DeployFromScratch is Script, Test { eigenPodImplementation = new EigenPod( ethPOSDeposit, eigenPodManager, - GOERLI_GENESIS_TIME + GOERLI_GENESIS_TIME, + SEMVER ); eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationImplementation = new DelegationManager(strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); - strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg); - avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg); + delegationImplementation = new DelegationManager( + strategyManager, + eigenPodManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + MIN_WITHDRAWAL_DELAY, + SEMVER + ); + strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg, SEMVER); + avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg, SEMVER); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, delegation, - eigenLayerPauserReg + eigenLayerPauserReg, + SEMVER ); rewardsCoordinatorImplementation = new RewardsCoordinator( - delegation, - strategyManager, - allocationManager, - eigenLayerPauserReg, - permissionController, - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, - REWARDS_COORDINATOR_MAX_REWARDS_DURATION, - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams( + delegation, + strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, + REWARDS_COORDINATOR_MAX_REWARDS_DURATION, + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP, + SEMVER + ) + ); + allocationManagerImplementation = new AllocationManager( + delegation, + eigenLayerPauserReg, + permissionController, + DEALLOCATION_DELAY, + ALLOCATION_CONFIGURATION_DELAY, + SEMVER ); - allocationManagerImplementation = new AllocationManager(delegation, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); - permissionControllerImplementation = new PermissionController(); + permissionControllerImplementation = new PermissionController(SEMVER); // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. { @@ -335,7 +359,7 @@ contract DeployFromScratch is Script, Test { ); // deploy StrategyBaseTVLLimits contract implementation - baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg); + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg, SEMVER); // create upgradeable proxies that each point to the implementation and initialize them for (uint256 i = 0; i < strategyConfigs.length; ++i) { if (strategyConfigs[i].tokenAddress == address(0)) { diff --git a/script/releases/Env.sol b/script/releases/Env.sol index e094d9ae3a..8f71ea1eda 100644 --- a/script/releases/Env.sol +++ b/script/releases/Env.sol @@ -53,6 +53,10 @@ library Env { * env */ + function version() internal view returns (string memory) { + return _envString("version"); + } + function executorMultisig() internal view returns (address) { return _envAddress("executorMultisig"); } @@ -301,6 +305,10 @@ library Env { return ZEnvHelpers.state().deployedImpl(name); } + function _envString(string memory key) private view returns (string memory) { + return ZEnvHelpers.state().envString(key); + } + function _envAddress(string memory key) private view returns (address) { return ZEnvHelpers.state().envAddress(key); } diff --git a/script/releases/v1.0.0-slashing/1-deployContracts.s.sol b/script/releases/v1.0.0-slashing/1-deployContracts.s.sol index 6c5828600a..d33b75e800 100644 --- a/script/releases/v1.0.0-slashing/1-deployContracts.s.sol +++ b/script/releases/v1.0.0-slashing/1-deployContracts.s.sol @@ -35,7 +35,7 @@ contract Deploy is EOADeployer { deployImpl({ name: type(PermissionController).name, - deployedTo: address(new PermissionController()) + deployedTo: address(new PermissionController(Env.version())) }); deployProxy({ @@ -56,7 +56,8 @@ contract Deploy is EOADeployer { _pauserRegistry: Env.impl.pauserRegistry(), _permissionController: Env.proxy.permissionController(), _DEALLOCATION_DELAY: Env.MIN_WITHDRAWAL_DELAY(), - _ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY() + _ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY(), + _version: Env.version() })) }); @@ -79,7 +80,8 @@ contract Deploy is EOADeployer { name: type(AVSDirectory).name, deployedTo: address(new AVSDirectory({ _delegation: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -91,31 +93,36 @@ contract Deploy is EOADeployer { _allocationManager: Env.proxy.allocationManager(), _pauserRegistry: Env.impl.pauserRegistry(), _permissionController: Env.proxy.permissionController(), - _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY() + _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY(), + _version: Env.version() })) }); deployImpl({ name: type(RewardsCoordinator).name, - deployedTo: address(new RewardsCoordinator({ - _delegationManager: Env.proxy.delegationManager(), - _strategyManager: Env.proxy.strategyManager(), - _allocationManager: Env.proxy.allocationManager(), - _pauserRegistry: Env.impl.pauserRegistry(), - _permissionController: Env.proxy.permissionController(), - _CALCULATION_INTERVAL_SECONDS: Env.CALCULATION_INTERVAL_SECONDS(), - _MAX_REWARDS_DURATION: Env.MAX_REWARDS_DURATION(), - _MAX_RETROACTIVE_LENGTH: Env.MAX_RETROACTIVE_LENGTH(), - _MAX_FUTURE_LENGTH: Env.MAX_FUTURE_LENGTH(), - _GENESIS_REWARDS_TIMESTAMP: Env.GENESIS_REWARDS_TIMESTAMP() - })) + deployedTo: address(new RewardsCoordinator( + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams({ + delegationManager: Env.proxy.delegationManager(), + strategyManager: Env.proxy.strategyManager(), + allocationManager: Env.proxy.allocationManager(), + pauserRegistry: Env.impl.pauserRegistry(), + permissionController: Env.proxy.permissionController(), + CALCULATION_INTERVAL_SECONDS: Env.CALCULATION_INTERVAL_SECONDS(), + MAX_REWARDS_DURATION: Env.MAX_REWARDS_DURATION(), + MAX_RETROACTIVE_LENGTH: Env.MAX_RETROACTIVE_LENGTH(), + MAX_FUTURE_LENGTH: Env.MAX_FUTURE_LENGTH(), + GENESIS_REWARDS_TIMESTAMP: Env.GENESIS_REWARDS_TIMESTAMP(), + version: Env.version() + }) + )) }); deployImpl({ name: type(StrategyManager).name, deployedTo: address(new StrategyManager({ _delegation: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -127,7 +134,8 @@ contract Deploy is EOADeployer { _ethPOS: Env.ethPOS(), _eigenPodBeacon: Env.beacon.eigenPod(), _delegationManager: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -136,7 +144,8 @@ contract Deploy is EOADeployer { deployedTo: address(new EigenPod({ _ethPOS: Env.ethPOS(), _eigenPodManager: Env.proxy.eigenPodManager(), - _GENESIS_TIME: Env.EIGENPOD_GENESIS_TIME() + _GENESIS_TIME: Env.EIGENPOD_GENESIS_TIME(), + _version: Env.version() })) }); @@ -146,7 +155,8 @@ contract Deploy is EOADeployer { name: type(StrategyBaseTVLLimits).name, deployedTo: address(new StrategyBaseTVLLimits({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -154,7 +164,8 @@ contract Deploy is EOADeployer { name: type(EigenStrategy).name, deployedTo: address(new EigenStrategy({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -162,7 +173,8 @@ contract Deploy is EOADeployer { name: type(StrategyFactory).name, deployedTo: address(new StrategyFactory({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -171,7 +183,8 @@ contract Deploy is EOADeployer { name: type(StrategyBase).name, deployedTo: address(new StrategyBase({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); diff --git a/script/releases/v1.0.1-slashing/1-eoa.s.sol b/script/releases/v1.0.1-slashing/1-eoa.s.sol index 82481da8c2..125d077055 100644 --- a/script/releases/v1.0.1-slashing/1-eoa.s.sol +++ b/script/releases/v1.0.1-slashing/1-eoa.s.sol @@ -21,7 +21,8 @@ contract Deploy is EOADeployer { _pauserRegistry: Env.impl.pauserRegistry(), _permissionController: Env.proxy.permissionController(), _DEALLOCATION_DELAY: Env.MIN_WITHDRAWAL_DELAY(), - _ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY() + _ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY(), + _version: Env.version() })) }); @@ -33,7 +34,8 @@ contract Deploy is EOADeployer { _allocationManager: Env.proxy.allocationManager(), _pauserRegistry: Env.impl.pauserRegistry(), _permissionController: Env.proxy.permissionController(), - _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY() + _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY(), + _version: Env.version() })) }); diff --git a/script/releases/v1.0.2-slashing-consolidated/1-deployContracts.s.sol b/script/releases/v1.0.2-slashing-consolidated/1-deployContracts.s.sol index 6c5828600a..d33b75e800 100644 --- a/script/releases/v1.0.2-slashing-consolidated/1-deployContracts.s.sol +++ b/script/releases/v1.0.2-slashing-consolidated/1-deployContracts.s.sol @@ -35,7 +35,7 @@ contract Deploy is EOADeployer { deployImpl({ name: type(PermissionController).name, - deployedTo: address(new PermissionController()) + deployedTo: address(new PermissionController(Env.version())) }); deployProxy({ @@ -56,7 +56,8 @@ contract Deploy is EOADeployer { _pauserRegistry: Env.impl.pauserRegistry(), _permissionController: Env.proxy.permissionController(), _DEALLOCATION_DELAY: Env.MIN_WITHDRAWAL_DELAY(), - _ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY() + _ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY(), + _version: Env.version() })) }); @@ -79,7 +80,8 @@ contract Deploy is EOADeployer { name: type(AVSDirectory).name, deployedTo: address(new AVSDirectory({ _delegation: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -91,31 +93,36 @@ contract Deploy is EOADeployer { _allocationManager: Env.proxy.allocationManager(), _pauserRegistry: Env.impl.pauserRegistry(), _permissionController: Env.proxy.permissionController(), - _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY() + _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY(), + _version: Env.version() })) }); deployImpl({ name: type(RewardsCoordinator).name, - deployedTo: address(new RewardsCoordinator({ - _delegationManager: Env.proxy.delegationManager(), - _strategyManager: Env.proxy.strategyManager(), - _allocationManager: Env.proxy.allocationManager(), - _pauserRegistry: Env.impl.pauserRegistry(), - _permissionController: Env.proxy.permissionController(), - _CALCULATION_INTERVAL_SECONDS: Env.CALCULATION_INTERVAL_SECONDS(), - _MAX_REWARDS_DURATION: Env.MAX_REWARDS_DURATION(), - _MAX_RETROACTIVE_LENGTH: Env.MAX_RETROACTIVE_LENGTH(), - _MAX_FUTURE_LENGTH: Env.MAX_FUTURE_LENGTH(), - _GENESIS_REWARDS_TIMESTAMP: Env.GENESIS_REWARDS_TIMESTAMP() - })) + deployedTo: address(new RewardsCoordinator( + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams({ + delegationManager: Env.proxy.delegationManager(), + strategyManager: Env.proxy.strategyManager(), + allocationManager: Env.proxy.allocationManager(), + pauserRegistry: Env.impl.pauserRegistry(), + permissionController: Env.proxy.permissionController(), + CALCULATION_INTERVAL_SECONDS: Env.CALCULATION_INTERVAL_SECONDS(), + MAX_REWARDS_DURATION: Env.MAX_REWARDS_DURATION(), + MAX_RETROACTIVE_LENGTH: Env.MAX_RETROACTIVE_LENGTH(), + MAX_FUTURE_LENGTH: Env.MAX_FUTURE_LENGTH(), + GENESIS_REWARDS_TIMESTAMP: Env.GENESIS_REWARDS_TIMESTAMP(), + version: Env.version() + }) + )) }); deployImpl({ name: type(StrategyManager).name, deployedTo: address(new StrategyManager({ _delegation: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -127,7 +134,8 @@ contract Deploy is EOADeployer { _ethPOS: Env.ethPOS(), _eigenPodBeacon: Env.beacon.eigenPod(), _delegationManager: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -136,7 +144,8 @@ contract Deploy is EOADeployer { deployedTo: address(new EigenPod({ _ethPOS: Env.ethPOS(), _eigenPodManager: Env.proxy.eigenPodManager(), - _GENESIS_TIME: Env.EIGENPOD_GENESIS_TIME() + _GENESIS_TIME: Env.EIGENPOD_GENESIS_TIME(), + _version: Env.version() })) }); @@ -146,7 +155,8 @@ contract Deploy is EOADeployer { name: type(StrategyBaseTVLLimits).name, deployedTo: address(new StrategyBaseTVLLimits({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -154,7 +164,8 @@ contract Deploy is EOADeployer { name: type(EigenStrategy).name, deployedTo: address(new EigenStrategy({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -162,7 +173,8 @@ contract Deploy is EOADeployer { name: type(StrategyFactory).name, deployedTo: address(new StrategyFactory({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -171,7 +183,8 @@ contract Deploy is EOADeployer { name: type(StrategyBase).name, deployedTo: address(new StrategyBase({ _strategyManager: Env.proxy.strategyManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); diff --git a/script/releases/v1.0.2-slashing/1-eoa.s.sol b/script/releases/v1.0.2-slashing/1-eoa.s.sol index 6a740cf9c3..86f02fe5fa 100644 --- a/script/releases/v1.0.2-slashing/1-eoa.s.sol +++ b/script/releases/v1.0.2-slashing/1-eoa.s.sol @@ -19,7 +19,8 @@ contract Deploy is EOADeployer { name: type(StrategyManager).name, deployedTo: address(new StrategyManager({ _delegation: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); diff --git a/script/releases/v1.0.3-slashing/1-eoa.s.sol b/script/releases/v1.0.3-slashing/1-eoa.s.sol index d9a5793aa3..a985aed5c3 100644 --- a/script/releases/v1.0.3-slashing/1-eoa.s.sol +++ b/script/releases/v1.0.3-slashing/1-eoa.s.sol @@ -25,7 +25,8 @@ contract Deploy is EOADeployer { _allocationManager: Env.proxy.allocationManager(), _pauserRegistry: Env.impl.pauserRegistry(), _permissionController: Env.proxy.permissionController(), - _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY() + _MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY(), + _version: Env.version() })) }); @@ -34,7 +35,8 @@ contract Deploy is EOADeployer { name: type(AVSDirectory).name, deployedTo: address(new AVSDirectory({ _delegation: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); @@ -43,25 +45,29 @@ contract Deploy is EOADeployer { name: type(StrategyManager).name, deployedTo: address(new StrategyManager({ _delegation: Env.proxy.delegationManager(), - _pauserRegistry: Env.impl.pauserRegistry() + _pauserRegistry: Env.impl.pauserRegistry(), + _version: Env.version() })) }); // Deploy RC deployImpl({ name: type(RewardsCoordinator).name, - deployedTo: address(new RewardsCoordinator({ - _delegationManager: Env.proxy.delegationManager(), - _strategyManager: Env.proxy.strategyManager(), - _allocationManager: Env.proxy.allocationManager(), - _pauserRegistry: Env.impl.pauserRegistry(), - _permissionController: Env.proxy.permissionController(), - _CALCULATION_INTERVAL_SECONDS: Env.CALCULATION_INTERVAL_SECONDS(), - _MAX_REWARDS_DURATION: Env.MAX_REWARDS_DURATION(), - _MAX_RETROACTIVE_LENGTH: Env.MAX_RETROACTIVE_LENGTH(), - _MAX_FUTURE_LENGTH: Env.MAX_FUTURE_LENGTH(), - _GENESIS_REWARDS_TIMESTAMP: Env.GENESIS_REWARDS_TIMESTAMP() - })) + deployedTo: address(new RewardsCoordinator( + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams({ + delegationManager: Env.proxy.delegationManager(), + strategyManager: Env.proxy.strategyManager(), + allocationManager: Env.proxy.allocationManager(), + pauserRegistry: Env.impl.pauserRegistry(), + permissionController: Env.proxy.permissionController(), + CALCULATION_INTERVAL_SECONDS: Env.CALCULATION_INTERVAL_SECONDS(), + MAX_REWARDS_DURATION: Env.MAX_REWARDS_DURATION(), + MAX_RETROACTIVE_LENGTH: Env.MAX_RETROACTIVE_LENGTH(), + MAX_FUTURE_LENGTH: Env.MAX_FUTURE_LENGTH(), + GENESIS_REWARDS_TIMESTAMP: Env.GENESIS_REWARDS_TIMESTAMP(), + version: Env.version() + }) + )) }); vm.stopBroadcast(); diff --git a/script/tasks/register_operator_to_operatorSet.s.sol b/script/tasks/register_operator_to_operatorSet.s.sol index 9ab8dc252a..292102ee64 100644 --- a/script/tasks/register_operator_to_operatorSet.s.sol +++ b/script/tasks/register_operator_to_operatorSet.s.sol @@ -64,7 +64,7 @@ contract RegisterOperatorToOperatorSets is Script, Test { // Register the Operator to the AVS avsDirectory.registerOperatorToAVS( - operator, ISignatureUtils.SignatureWithSaltAndExpiry(abi.encodePacked(r, s, v), bytes32(uint256(0) + 1), expiry) + operator, ISignatureUtilsMixinTypes.SignatureWithSaltAndExpiry(abi.encodePacked(r, s, v), bytes32(uint256(0) + 1), expiry) ); // Deploy and set registrar. diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index 408b4204d6..56751522d4 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -50,6 +50,7 @@ contract ExistingDeploymentParser is Script, Logger { /// EigenLayer Contract Parameters /// ----------------------------------------------------------------------- + string public SEMVER; /// @dev AllocationManager uint256 ALLOCATION_MANAGER_INIT_PAUSED_STATUS; uint32 DEALLOCATION_DELAY; @@ -193,6 +194,8 @@ contract ExistingDeploymentParser is Script, Logger { // READ JSON CONFIG DATA string memory json = cheats.readFile(existingDeploymentInfoPath); + SEMVER = stdJson.readString(json, ".parameters.semver"); + // check that the chainID matches the one in the config uint256 configChainId = json.readUint(".chainInfo.chainId"); assertEq(configChainId, currentChainId, "You are on the wrong chain for this config"); @@ -211,7 +214,7 @@ contract ExistingDeploymentParser is Script, Logger { eigenLayerPauserReg = PauserRegistry(json.readAddress(".addresses.eigenLayerPauserReg")); // FIXME: hotfix - remove later... - permissionControllerImplementation = new PermissionController(); + permissionControllerImplementation = new PermissionController(SEMVER); permissionController = PermissionController( address(new TransparentUpgradeableProxy(address(permissionControllerImplementation), address(eigenLayerProxyAdmin), "")) ); @@ -221,7 +224,8 @@ contract ExistingDeploymentParser is Script, Logger { eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, - ALLOCATION_CONFIGURATION_DELAY + ALLOCATION_CONFIGURATION_DELAY, + SEMVER ); allocationManager = AllocationManager( address(new TransparentUpgradeableProxy(address(allocationManagerImplementation), address(eigenLayerProxyAdmin), "")) diff --git a/src/contracts/core/AVSDirectory.sol b/src/contracts/core/AVSDirectory.sol index 0e9af8741f..86e5c2920d 100644 --- a/src/contracts/core/AVSDirectory.sol +++ b/src/contracts/core/AVSDirectory.sol @@ -5,7 +5,7 @@ import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; -import "../mixins/SignatureUtils.sol"; +import "../mixins/SignatureUtilsMixin.sol"; import "../permissions/Pausable.sol"; import "./AVSDirectoryStorage.sol"; @@ -15,7 +15,7 @@ contract AVSDirectory is Pausable, AVSDirectoryStorage, ReentrancyGuardUpgradeable, - SignatureUtils + SignatureUtilsMixin { /** * @@ -29,8 +29,9 @@ contract AVSDirectory is */ constructor( IDelegationManager _delegation, - IPauserRegistry _pauserRegistry - ) AVSDirectoryStorage(_delegation) Pausable(_pauserRegistry) { + IPauserRegistry _pauserRegistry, + string memory _version + ) AVSDirectoryStorage(_delegation) Pausable(_pauserRegistry) SignatureUtilsMixin(_version) { _disableInitializers(); } @@ -70,7 +71,7 @@ contract AVSDirectory is /// @inheritdoc IAVSDirectory function registerOperatorToAVS( address operator, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ISignatureUtilsMixinTypes.SignatureWithSaltAndExpiry memory operatorSignature ) external override onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS) { // Assert that the `operator` is not actively registered to the AVS. require( diff --git a/src/contracts/core/AllocationManager.sol b/src/contracts/core/AllocationManager.sol index 873e25ee70..7912227cc0 100644 --- a/src/contracts/core/AllocationManager.sol +++ b/src/contracts/core/AllocationManager.sol @@ -6,6 +6,7 @@ import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; import "../mixins/PermissionControllerMixin.sol"; +import "../mixins/SemVerMixin.sol"; import "../permissions/Pausable.sol"; import "../libraries/SlashingLib.sol"; import "../libraries/OperatorSetLib.sol"; @@ -17,7 +18,8 @@ contract AllocationManager is Pausable, AllocationManagerStorage, ReentrancyGuardUpgradeable, - PermissionControllerMixin + PermissionControllerMixin, + SemVerMixin { using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; using EnumerableSet for *; @@ -41,11 +43,13 @@ contract AllocationManager is IPauserRegistry _pauserRegistry, IPermissionController _permissionController, uint32 _DEALLOCATION_DELAY, - uint32 _ALLOCATION_CONFIGURATION_DELAY + uint32 _ALLOCATION_CONFIGURATION_DELAY, + string memory _version ) AllocationManagerStorage(_delegation, _DEALLOCATION_DELAY, _ALLOCATION_CONFIGURATION_DELAY) Pausable(_pauserRegistry) PermissionControllerMixin(_permissionController) + SemVerMixin(_version) { _disableInitializers(); } diff --git a/src/contracts/core/DelegationManager.sol b/src/contracts/core/DelegationManager.sol index 1dbb82401d..2e7828adc5 100644 --- a/src/contracts/core/DelegationManager.sol +++ b/src/contracts/core/DelegationManager.sol @@ -5,7 +5,7 @@ import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; -import "../mixins/SignatureUtils.sol"; +import "../mixins/SignatureUtilsMixin.sol"; import "../mixins/PermissionControllerMixin.sol"; import "../permissions/Pausable.sol"; import "../libraries/SlashingLib.sol"; @@ -28,8 +28,8 @@ contract DelegationManager is Pausable, DelegationManagerStorage, ReentrancyGuardUpgradeable, - SignatureUtils, - PermissionControllerMixin + PermissionControllerMixin, + SignatureUtilsMixin { using SlashingLib for *; using Snapshots for Snapshots.DefaultZeroHistory; @@ -69,11 +69,13 @@ contract DelegationManager is IAllocationManager _allocationManager, IPauserRegistry _pauserRegistry, IPermissionController _permissionController, - uint32 _MIN_WITHDRAWAL_DELAY + uint32 _MIN_WITHDRAWAL_DELAY, + string memory _version ) DelegationManagerStorage(_strategyManager, _eigenPodManager, _allocationManager, _MIN_WITHDRAWAL_DELAY) Pausable(_pauserRegistry) PermissionControllerMixin(_permissionController) + SignatureUtilsMixin(_version) { _disableInitializers(); } diff --git a/src/contracts/core/RewardsCoordinator.sol b/src/contracts/core/RewardsCoordinator.sol index 13e2569d59..24ee4af825 100644 --- a/src/contracts/core/RewardsCoordinator.sol +++ b/src/contracts/core/RewardsCoordinator.sol @@ -10,6 +10,7 @@ import "../libraries/Merkle.sol"; import "../permissions/Pausable.sol"; import "./RewardsCoordinatorStorage.sol"; import "../mixins/PermissionControllerMixin.sol"; +import "../mixins/SemVerMixin.sol"; /** * @title RewardsCoordinator @@ -26,7 +27,8 @@ contract RewardsCoordinator is Pausable, ReentrancyGuardUpgradeable, RewardsCoordinatorStorage, - PermissionControllerMixin + PermissionControllerMixin, + SemVerMixin { using SafeERC20 for IERC20; @@ -42,29 +44,21 @@ contract RewardsCoordinator is /// @dev Sets the immutable variables for the contract constructor( - IDelegationManager _delegationManager, - IStrategyManager _strategyManager, - IAllocationManager _allocationManager, - IPauserRegistry _pauserRegistry, - IPermissionController _permissionController, - uint32 _CALCULATION_INTERVAL_SECONDS, - uint32 _MAX_REWARDS_DURATION, - uint32 _MAX_RETROACTIVE_LENGTH, - uint32 _MAX_FUTURE_LENGTH, - uint32 _GENESIS_REWARDS_TIMESTAMP + RewardsCoordinatorConstructorParams memory params ) RewardsCoordinatorStorage( - _delegationManager, - _strategyManager, - _allocationManager, - _CALCULATION_INTERVAL_SECONDS, - _MAX_REWARDS_DURATION, - _MAX_RETROACTIVE_LENGTH, - _MAX_FUTURE_LENGTH, - _GENESIS_REWARDS_TIMESTAMP + params.delegationManager, + params.strategyManager, + params.allocationManager, + params.CALCULATION_INTERVAL_SECONDS, + params.MAX_REWARDS_DURATION, + params.MAX_RETROACTIVE_LENGTH, + params.MAX_FUTURE_LENGTH, + params.GENESIS_REWARDS_TIMESTAMP ) - Pausable(_pauserRegistry) - PermissionControllerMixin(_permissionController) + Pausable(params.pauserRegistry) + PermissionControllerMixin(params.permissionController) + SemVerMixin(params.version) { _disableInitializers(); } diff --git a/src/contracts/core/RewardsCoordinatorStorage.sol b/src/contracts/core/RewardsCoordinatorStorage.sol index 6c519214f9..31d4b61f1a 100644 --- a/src/contracts/core/RewardsCoordinatorStorage.sol +++ b/src/contracts/core/RewardsCoordinatorStorage.sol @@ -2,9 +2,6 @@ pragma solidity ^0.8.27; import "../interfaces/IRewardsCoordinator.sol"; -import "../interfaces/IDelegationManager.sol"; -import "../interfaces/IStrategyManager.sol"; -import "../interfaces/IAllocationManager.sol"; /** * @title Storage variables for the `RewardsCoordinator` contract. diff --git a/src/contracts/core/StrategyManager.sol b/src/contracts/core/StrategyManager.sol index 49ed6c5e87..c1b5bbada0 100644 --- a/src/contracts/core/StrategyManager.sol +++ b/src/contracts/core/StrategyManager.sol @@ -6,7 +6,7 @@ import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "../mixins/SignatureUtils.sol"; +import "../mixins/SignatureUtilsMixin.sol"; import "../interfaces/IEigenPodManager.sol"; import "../permissions/Pausable.sol"; import "./StrategyManagerStorage.sol"; @@ -26,7 +26,7 @@ contract StrategyManager is ReentrancyGuardUpgradeable, Pausable, StrategyManagerStorage, - SignatureUtils + SignatureUtilsMixin { using SlashingLib for *; using SafeERC20 for IERC20; @@ -53,8 +53,9 @@ contract StrategyManager is */ constructor( IDelegationManager _delegation, - IPauserRegistry _pauserRegistry - ) StrategyManagerStorage(_delegation) Pausable(_pauserRegistry) { + IPauserRegistry _pauserRegistry, + string memory _version + ) StrategyManagerStorage(_delegation) Pausable(_pauserRegistry) SignatureUtilsMixin(_version) { _disableInitializers(); } diff --git a/src/contracts/interfaces/IAVSDirectory.sol b/src/contracts/interfaces/IAVSDirectory.sol index 1276682ca1..4d48aa93df 100644 --- a/src/contracts/interfaces/IAVSDirectory.sol +++ b/src/contracts/interfaces/IAVSDirectory.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; -import "./ISignatureUtils.sol"; +import "./ISignatureUtilsMixin.sol"; import "./IPauserRegistry.sol"; import "./IStrategy.sol"; @@ -53,7 +53,7 @@ interface IAVSDirectoryEvents is IAVSDirectoryTypes { event AVSMetadataURIUpdated(address indexed avs, string metadataURI); } -interface IAVSDirectory is IAVSDirectoryEvents, IAVSDirectoryErrors, ISignatureUtils { +interface IAVSDirectory is IAVSDirectoryEvents, IAVSDirectoryErrors, ISignatureUtilsMixin { /** * * EXTERNAL FUNCTIONS @@ -98,7 +98,7 @@ interface IAVSDirectory is IAVSDirectoryEvents, IAVSDirectoryErrors, ISignatureU */ function registerOperatorToAVS( address operator, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ISignatureUtilsMixinTypes.SignatureWithSaltAndExpiry memory operatorSignature ) external; /** diff --git a/src/contracts/interfaces/IAllocationManager.sol b/src/contracts/interfaces/IAllocationManager.sol index cfbf18df2a..99cf6425ab 100644 --- a/src/contracts/interfaces/IAllocationManager.sol +++ b/src/contracts/interfaces/IAllocationManager.sol @@ -5,6 +5,7 @@ import {OperatorSet} from "../libraries/OperatorSetLib.sol"; import "./IPauserRegistry.sol"; import "./IStrategy.sol"; import "./IAVSRegistrar.sol"; +import "./ISemVerMixin.sol"; interface IAllocationManagerErrors { /// Input Validation @@ -210,7 +211,7 @@ interface IAllocationManagerEvents is IAllocationManagerTypes { event StrategyRemovedFromOperatorSet(OperatorSet operatorSet, IStrategy strategy); } -interface IAllocationManager is IAllocationManagerErrors, IAllocationManagerEvents { +interface IAllocationManager is IAllocationManagerErrors, IAllocationManagerEvents, ISemVerMixin { /** * @dev Initializes the initial owner and paused status. */ diff --git a/src/contracts/interfaces/IDelegationManager.sol b/src/contracts/interfaces/IDelegationManager.sol index 03df3ce3c5..3a562cded9 100644 --- a/src/contracts/interfaces/IDelegationManager.sol +++ b/src/contracts/interfaces/IDelegationManager.sol @@ -3,7 +3,7 @@ pragma solidity >=0.5.0; import "./IStrategy.sol"; import "./IPauserRegistry.sol"; -import "./ISignatureUtils.sol"; +import "./ISignatureUtilsMixin.sol"; import "../libraries/SlashingLib.sol"; interface IDelegationManagerErrors { @@ -185,7 +185,7 @@ interface IDelegationManagerEvents is IDelegationManagerTypes { * - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a single operator at a time) * - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the withdrawal process, initiated through the StrategyManager) */ -interface IDelegationManager is ISignatureUtils, IDelegationManagerErrors, IDelegationManagerEvents { +interface IDelegationManager is ISignatureUtilsMixin, IDelegationManagerErrors, IDelegationManagerEvents { /** * @dev Initializes the initial owner and paused status. */ diff --git a/src/contracts/interfaces/IEigenPod.sol b/src/contracts/interfaces/IEigenPod.sol index 5f354e7cd4..83dc8d8211 100644 --- a/src/contracts/interfaces/IEigenPod.sol +++ b/src/contracts/interfaces/IEigenPod.sol @@ -4,6 +4,7 @@ pragma solidity >=0.5.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../libraries/BeaconChainProofs.sol"; +import "./ISemVerMixin.sol"; import "./IEigenPodManager.sol"; interface IEigenPodErrors { @@ -138,7 +139,7 @@ interface IEigenPodEvents is IEigenPodTypes { * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose * to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts */ -interface IEigenPod is IEigenPodErrors, IEigenPodEvents { +interface IEigenPod is IEigenPodErrors, IEigenPodEvents, ISemVerMixin { /// @notice Used to initialize the pointers to contracts crucial to the pod's functionality, in beacon proxy construction from EigenPodManager function initialize( address owner diff --git a/src/contracts/interfaces/IEigenPodManager.sol b/src/contracts/interfaces/IEigenPodManager.sol index baf574cde8..afb384b744 100644 --- a/src/contracts/interfaces/IEigenPodManager.sol +++ b/src/contracts/interfaces/IEigenPodManager.sol @@ -8,6 +8,7 @@ import "./IEigenPod.sol"; import "./IShareManager.sol"; import "./IPausable.sol"; import "./IStrategy.sol"; +import "./ISemVerMixin.sol"; interface IEigenPodManagerErrors { /// @dev Thrown when caller is not a EigenPod. @@ -85,7 +86,8 @@ interface IEigenPodManager is IEigenPodManagerEvents, IEigenPodManagerTypes, IShareManager, - IPausable + IPausable, + ISemVerMixin { /** * @notice Creates an EigenPod for the sender. diff --git a/src/contracts/interfaces/IPermissionController.sol b/src/contracts/interfaces/IPermissionController.sol index 5d4be806d6..81a28cfcce 100644 --- a/src/contracts/interfaces/IPermissionController.sol +++ b/src/contracts/interfaces/IPermissionController.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; +import "./ISemVerMixin.sol"; + interface IPermissionControllerErrors { /// @notice Thrown when the caller is not the admin error NotAdmin(); @@ -40,7 +42,7 @@ interface IPermissionControllerEvents { event AdminRemoved(address indexed account, address admin); } -interface IPermissionController is IPermissionControllerErrors, IPermissionControllerEvents { +interface IPermissionController is IPermissionControllerErrors, IPermissionControllerEvents, ISemVerMixin { /** * @notice Sets a pending admin of an account * @param account to set pending admin for diff --git a/src/contracts/interfaces/IRewardsCoordinator.sol b/src/contracts/interfaces/IRewardsCoordinator.sol index c019c8efe0..38d310eca7 100644 --- a/src/contracts/interfaces/IRewardsCoordinator.sol +++ b/src/contracts/interfaces/IRewardsCoordinator.sol @@ -2,8 +2,14 @@ pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import "./IAllocationManager.sol"; +import "./IDelegationManager.sol"; +import "./IStrategyManager.sol"; import "./IPauserRegistry.sol"; +import "./IPermissionController.sol"; import "./IStrategy.sol"; +import "./ISemVerMixin.sol"; interface IRewardsCoordinatorErrors { /// @dev Thrown when msg.sender is not allowed to call a function @@ -234,6 +240,35 @@ interface IRewardsCoordinatorTypes { bytes[] tokenTreeProofs; TokenTreeMerkleLeaf[] tokenLeaves; } + + /** + * @notice Parameters for the RewardsCoordinator constructor + * @param delegationManager The address of the DelegationManager contract + * @param strategyManager The address of the StrategyManager contract + * @param allocationManager The address of the AllocationManager contract + * @param pauserRegistry The address of the PauserRegistry contract + * @param permissionController The address of the PermissionController contract + * @param CALCULATION_INTERVAL_SECONDS The interval at which rewards are calculated + * @param MAX_REWARDS_DURATION The maximum duration of a rewards submission + * @param MAX_RETROACTIVE_LENGTH The maximum retroactive length of a rewards submission + * @param MAX_FUTURE_LENGTH The maximum future length of a rewards submission + * @param GENESIS_REWARDS_TIMESTAMP The timestamp at which rewards are first calculated + * @param version The semantic version of the contract (e.g. "v1.2.3") + * @dev Needed to avoid stack-too-deep errors + */ + struct RewardsCoordinatorConstructorParams { + IDelegationManager delegationManager; + IStrategyManager strategyManager; + IAllocationManager allocationManager; + IPauserRegistry pauserRegistry; + IPermissionController permissionController; + uint32 CALCULATION_INTERVAL_SECONDS; + uint32 MAX_REWARDS_DURATION; + uint32 MAX_RETROACTIVE_LENGTH; + uint32 MAX_FUTURE_LENGTH; + uint32 GENESIS_REWARDS_TIMESTAMP; + string version; + } } interface IRewardsCoordinatorEvents is IRewardsCoordinatorTypes { @@ -353,7 +388,7 @@ interface IRewardsCoordinatorEvents is IRewardsCoordinatorTypes { * Calculations are performed based on the completed RewardsSubmission, with the results posted in * a Merkle root against which Stakers & Operators can make claims. */ -interface IRewardsCoordinator is IRewardsCoordinatorErrors, IRewardsCoordinatorEvents { +interface IRewardsCoordinator is IRewardsCoordinatorErrors, IRewardsCoordinatorEvents, ISemVerMixin { /** * @dev Initializes the addresses of the initial owner, pauser registry, rewardsUpdater and * configures the initial paused status, activationDelay, and defaultOperatorSplitBips. diff --git a/src/contracts/interfaces/ISemVerMixin.sol b/src/contracts/interfaces/ISemVerMixin.sol new file mode 100644 index 0000000000..206cf38d46 --- /dev/null +++ b/src/contracts/interfaces/ISemVerMixin.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +/// @title ISemVerMixin +/// @notice A mixin interface that provides semantic versioning functionality. +/// @dev Follows SemVer 2.0.0 specification (https://semver.org/) +interface ISemVerMixin { + /// @notice Returns the semantic version string of the contract. + /// @return The version string in SemVer format (e.g., "v1.1.1") + function version() external view returns (string memory); +} diff --git a/src/contracts/interfaces/IShareManager.sol b/src/contracts/interfaces/IShareManager.sol index e7c9501baf..4d2d66e9ff 100644 --- a/src/contracts/interfaces/IShareManager.sol +++ b/src/contracts/interfaces/IShareManager.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../libraries/SlashingLib.sol"; import "./IStrategy.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title Interface for a `IShareManager` contract. diff --git a/src/contracts/interfaces/ISignatureUtils.sol b/src/contracts/interfaces/ISignatureUtils.sol deleted file mode 100644 index 9e1ac2b45d..0000000000 --- a/src/contracts/interfaces/ISignatureUtils.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0; - -/** - * @title The interface for common signature utilities. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - */ -interface ISignatureUtils { - error InvalidSignature(); - error SignatureExpired(); - - // @notice Struct that bundles together a signature and an expiration time for the signature. Used primarily for stack management. - struct SignatureWithExpiry { - // the signature itself, formatted as a single bytes object - bytes signature; - // the expiration timestamp (UTC) of the signature - uint256 expiry; - } - - // @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature. Used primarily for stack management. - struct SignatureWithSaltAndExpiry { - // the signature itself, formatted as a single bytes object - bytes signature; - // the salt used to generate the signature - bytes32 salt; - // the expiration timestamp (UTC) of the signature - uint256 expiry; - } -} diff --git a/src/contracts/interfaces/ISignatureUtilsMixin.sol b/src/contracts/interfaces/ISignatureUtilsMixin.sol new file mode 100644 index 0000000000..7b9c8c372f --- /dev/null +++ b/src/contracts/interfaces/ISignatureUtilsMixin.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity >=0.5.0; + +import "./ISemVerMixin.sol"; + +interface ISignatureUtilsMixinErrors { + /// @notice Thrown when a signature is invalid. + error InvalidSignature(); + /// @notice Thrown when a signature has expired. + error SignatureExpired(); +} + +interface ISignatureUtilsMixinTypes { + /// @notice Struct that bundles together a signature and an expiration time for the signature. + /// @dev Used primarily for stack management. + struct SignatureWithExpiry { + // the signature itself, formatted as a single bytes object + bytes signature; + // the expiration timestamp (UTC) of the signature + uint256 expiry; + } + + /// @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature. + /// @dev Used primarily for stack management. + struct SignatureWithSaltAndExpiry { + // the signature itself, formatted as a single bytes object + bytes signature; + // the salt used to generate the signature + bytes32 salt; + // the expiration timestamp (UTC) of the signature + uint256 expiry; + } +} + +/** + * @title The interface for common signature utilities. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + */ +interface ISignatureUtilsMixin is ISignatureUtilsMixinErrors, ISignatureUtilsMixinTypes, ISemVerMixin { + /// @notice Computes the EIP-712 domain separator used for signature validation. + /// @dev The domain separator is computed according to EIP-712 specification, using: + /// - The hardcoded name "EigenLayer" + /// - The contract's version string + /// - The current chain ID + /// - This contract's address + /// @return The 32-byte domain separator hash used in EIP-712 structured data signing. + /// @dev See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator. + function domainSeparator() external view returns (bytes32); +} diff --git a/src/contracts/interfaces/IStrategy.sol b/src/contracts/interfaces/IStrategy.sol index 3052cba1c4..a5224d1322 100644 --- a/src/contracts/interfaces/IStrategy.sol +++ b/src/contracts/interfaces/IStrategy.sol @@ -3,7 +3,7 @@ pragma solidity >=0.5.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../libraries/SlashingLib.sol"; - +import "./ISemVerMixin.sol"; interface IStrategyErrors { /// @dev Thrown when called by an account that is not strategy manager. error OnlyStrategyManager(); @@ -47,7 +47,7 @@ interface IStrategyEvents { * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @notice Custom `Strategy` implementations may expand extensively on this interface. */ -interface IStrategy is IStrategyErrors, IStrategyEvents { +interface IStrategy is IStrategyErrors, IStrategyEvents, ISemVerMixin { /** * @notice Used to deposit tokens into this Strategy * @param token is the ERC20 token being deposited diff --git a/src/contracts/interfaces/IStrategyFactory.sol b/src/contracts/interfaces/IStrategyFactory.sol index 137659cc34..c019695b4a 100644 --- a/src/contracts/interfaces/IStrategyFactory.sol +++ b/src/contracts/interfaces/IStrategyFactory.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IStrategy.sol"; +import "./ISemVerMixin.sol"; /** * @title Interface for the `StrategyFactory` contract. @@ -11,7 +12,7 @@ import "./IStrategy.sol"; * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @dev This may not be compatible with non-standard ERC20 tokens. Caution is warranted. */ -interface IStrategyFactory { +interface IStrategyFactory is ISemVerMixin { /// @dev Thrown when attempting to deploy a strategy for a blacklisted token. error BlacklistedToken(); /// @dev Thrown when attempting to deploy a strategy that already exists. diff --git a/src/contracts/interfaces/IStrategyManager.sol b/src/contracts/interfaces/IStrategyManager.sol index eeac883c37..2af48d4386 100644 --- a/src/contracts/interfaces/IStrategyManager.sol +++ b/src/contracts/interfaces/IStrategyManager.sol @@ -5,6 +5,7 @@ import "./IStrategy.sol"; import "./IShareManager.sol"; import "./IDelegationManager.sol"; import "./IEigenPodManager.sol"; +import "./ISemVerMixin.sol"; interface IStrategyManagerErrors { /// @dev Thrown when total strategies deployed exceeds max. @@ -56,7 +57,7 @@ interface IStrategyManagerEvents { * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @notice See the `StrategyManager` contract itself for implementation details. */ -interface IStrategyManager is IStrategyManagerErrors, IStrategyManagerEvents, IShareManager { +interface IStrategyManager is IStrategyManagerErrors, IStrategyManagerEvents, IShareManager, ISemVerMixin { /** * @notice Initializes the strategy manager contract. Sets the `pauserRegistry` (currently **not** modifiable after being set), * and transfers contract ownership to the specified `initialOwner`. diff --git a/src/contracts/mixins/SemVerMixin.sol b/src/contracts/mixins/SemVerMixin.sol new file mode 100644 index 0000000000..c955de4f8b --- /dev/null +++ b/src/contracts/mixins/SemVerMixin.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import "../interfaces/ISemVerMixin.sol"; +import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol"; + +/// @title SemVerMixin +/// @notice A mixin contract that provides semantic versioning functionality. +/// @dev Follows SemVer 2.0.0 specification (https://semver.org/). +abstract contract SemVerMixin is ISemVerMixin { + using ShortStringsUpgradeable for *; + + /// @notice The semantic version string for this contract, stored as a ShortString for gas efficiency. + /// @dev Follows SemVer 2.0.0 specification (https://semver.org/). Prefixed with 'v' (e.g., "v1.2.3"). + ShortString internal immutable _VERSION; + + /// @notice Initializes the contract with a semantic version string. + /// @param _version The SemVer-formatted version string (e.g., "v1.2.3") + /// @dev Version should follow SemVer 2.0.0 format with 'v' prefix: vMAJOR.MINOR.PATCH + constructor( + string memory _version + ) { + _VERSION = _version.toShortString(); + } + + /// @inheritdoc ISemVerMixin + function version() public view virtual returns (string memory) { + return _VERSION.toString(); + } + + /// @notice Returns the major version of the contract. + /// @dev Supports single digit major versions (e.g., "v1" for version "v1.2.3") + /// @return The major version string (e.g., "v1" for version "v1.2.3") + function _majorVersion() internal view returns (string memory) { + bytes memory v = bytes(_VERSION.toString()); + return string(bytes.concat(v[0], v[1])); + } +} diff --git a/src/contracts/mixins/SignatureUtils.sol b/src/contracts/mixins/SignatureUtils.sol deleted file mode 100644 index 18f9c89844..0000000000 --- a/src/contracts/mixins/SignatureUtils.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.0; - -import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol"; - -import "../interfaces/ISignatureUtils.sol"; - -/// @title SignatureUtils -/// @notice A mixin to provide EIP-712 signature validation utilities. -/// @dev Domain name is hardcoded to "EigenLayer". -abstract contract SignatureUtils is ISignatureUtils { - using SignatureCheckerUpgradeable for address; - - /// CONSTANTS - - /// @notice The EIP-712 typehash for the contract's domain. - bytes32 internal constant EIP712_DOMAIN_TYPEHASH = - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); - - /// @dev Returns the original chain ID from the time the contract was deployed. - uint256 internal immutable _INITIAL_CHAIN_ID; - - /// @dev Returns the original domain separator from the time the contract was deployed. - bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR; - - /// CONSTRUCTION - - constructor() { - _INITIAL_CHAIN_ID = block.chainid; - _INITIAL_DOMAIN_SEPARATOR = _calculateDomainSeparator(); - } - - /// EXTERNAL FUNCTIONS - - /** - * @notice Returns the current EIP-712 domain separator for this contract. - * - * @dev The domain separator will change in the event of a fork that changes the ChainID. - * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. - * for more detailed information please read EIP-712. - * @dev Use `_calculateDomainSeparator` rather than using this function. - */ - function domainSeparator() public view virtual returns (bytes32) { - /// forgefmt: disable-next-item - return block.chainid == _INITIAL_CHAIN_ID - // If the chain ID is the same, return the original domain separator. - ? _INITIAL_DOMAIN_SEPARATOR - // If the chain ID is different, return the new domain separator. - : _calculateDomainSeparator(); - } - - /// INTERNAL HELPERS - - /// @dev Helper for calculating the contract's domain separator. - function _calculateDomainSeparator() internal view returns (bytes32) { - /// forgefmt: disable-next-item - return - keccak256( - abi.encode( - EIP712_DOMAIN_TYPEHASH, - keccak256(bytes("EigenLayer")), - block.chainid, - address(this) - ) - ); - } - - /// @dev Helper for creating valid EIP-712 signable digests. - function _calculateSignableDigest( - bytes32 hash - ) internal view returns (bytes32) { - return keccak256(abi.encodePacked("\x19\x01", domainSeparator(), hash)); - } - - /// @dev Helper for checking if a signature is valid, reverts if not valid. - function _checkIsValidSignatureNow( - address signer, - bytes32 signableDigest, - bytes memory signature, - uint256 expiry - ) internal view { - require(expiry >= block.timestamp, SignatureExpired()); - require(signer.isValidSignatureNow(signableDigest, signature), InvalidSignature()); - } -} diff --git a/src/contracts/mixins/SignatureUtilsMixin.sol b/src/contracts/mixins/SignatureUtilsMixin.sol new file mode 100644 index 0000000000..10b33ad61c --- /dev/null +++ b/src/contracts/mixins/SignatureUtilsMixin.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol"; +import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol"; + +import "../interfaces/ISignatureUtilsMixin.sol"; +import "./SemVerMixin.sol"; + +/// @dev The EIP-712 domain type hash used for computing the domain separator +/// See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator +bytes32 constant EIP712_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + +/// @title SignatureUtilsMixin +/// @notice A mixin contract that provides utilities for validating signatures according to EIP-712 and EIP-1271 standards. +/// @dev The domain name is hardcoded to "EigenLayer". This contract implements signature validation functionality that can be +/// inherited by other contracts. The domain separator uses the major version (e.g., "v1") to maintain EIP-712 +/// signature compatibility across minor and patch version updates. +abstract contract SignatureUtilsMixin is ISignatureUtilsMixin, SemVerMixin { + using SignatureCheckerUpgradeable for address; + + /// @notice Initializes the contract with a semantic version string. + /// @param _version The SemVer-formatted version string (e.g., "v1.1.1") to use for this contract's domain separator. + /// @dev Version should follow SemVer 2.0.0 format with 'v' prefix: vMAJOR.MINOR.PATCH. + /// Only the major version component is used in the domain separator to maintain signature compatibility + /// across minor and patch version updates. + constructor( + string memory _version + ) SemVerMixin(_version) {} + + /// EXTERNAL FUNCTIONS /// + + /// @inheritdoc ISignatureUtilsMixin + function domainSeparator() public view virtual returns (bytes32) { + // forgefmt: disable-next-item + return + keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256(bytes("EigenLayer")), + keccak256(bytes(_majorVersion())), + block.chainid, + address(this) + ) + ); + } + + /// INTERNAL HELPERS /// + + /// @notice Creates a digest that can be signed using EIP-712. + /// @dev Prepends the EIP-712 prefix ("\x19\x01") and domain separator to the input hash. + /// This follows the EIP-712 specification for creating structured data hashes. + /// See https://eips.ethereum.org/EIPS/eip-712#specification. + /// @param hash The hash of the typed data to be signed. + /// @return The complete digest that should be signed according to EIP-712. + function _calculateSignableDigest( + bytes32 hash + ) internal view returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x01", domainSeparator(), hash)); + } + + /// @notice Validates a signature against a signer and digest, with an expiry timestamp. + /// @dev Reverts if the signature is invalid or expired. Uses EIP-1271 for smart contract signers. + /// For EOA signers, validates ECDSA signatures directly. + /// For contract signers, calls isValidSignature according to EIP-1271. + /// See https://eips.ethereum.org/EIPS/eip-1271#specification. + /// @param signer The address that should have signed the digest. + /// @param signableDigest The digest that was signed, created via _calculateSignableDigest. + /// @param signature The signature bytes to validate. + /// @param expiry The timestamp after which the signature is no longer valid. + function _checkIsValidSignatureNow( + address signer, + bytes32 signableDigest, + bytes memory signature, + uint256 expiry + ) internal view { + // First, check if the signature has expired by comparing the expiry timestamp + // against the current block timestamp. + require(expiry >= block.timestamp, SignatureExpired()); + + // Next, verify that the signature is valid for the given signer and digest. + // For EOA signers, this performs standard ECDSA signature verification. + // For contract signers, this calls the EIP-1271 isValidSignature method. + require(signer.isValidSignatureNow(signableDigest, signature), InvalidSignature()); + } +} diff --git a/src/contracts/permissions/PermissionController.sol b/src/contracts/permissions/PermissionController.sol index 46bdea5bde..ee367d79d8 100644 --- a/src/contracts/permissions/PermissionController.sol +++ b/src/contracts/permissions/PermissionController.sol @@ -2,9 +2,10 @@ pragma solidity ^0.8.27; import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; +import "../mixins/SemVerMixin.sol"; import "./PermissionControllerStorage.sol"; -contract PermissionController is Initializable, PermissionControllerStorage { +contract PermissionController is Initializable, SemVerMixin, PermissionControllerStorage { using EnumerableSet for *; modifier onlyAdmin( @@ -19,7 +20,9 @@ contract PermissionController is Initializable, PermissionControllerStorage { * INITIALIZING FUNCTIONS * */ - constructor() { + constructor( + string memory _version + ) SemVerMixin(_version) { _disableInitializers(); } diff --git a/src/contracts/pods/EigenPod.sol b/src/contracts/pods/EigenPod.sol index 1066b2fbfb..c92bf9191e 100644 --- a/src/contracts/pods/EigenPod.sol +++ b/src/contracts/pods/EigenPod.sol @@ -8,6 +8,8 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../libraries/BeaconChainProofs.sol"; import "../libraries/BytesLib.sol"; +import "../mixins/SemVerMixin.sol"; + import "../interfaces/IETHPOSDeposit.sol"; import "../interfaces/IEigenPodManager.sol"; import "../interfaces/IPausable.sol"; @@ -23,7 +25,13 @@ import "./EigenPodStorage.sol"; * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose * to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts */ -contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingConstants, EigenPodStorage { +contract EigenPod is + Initializable, + ReentrancyGuardUpgradeable, + EigenPodPausingConstants, + EigenPodStorage, + SemVerMixin +{ using BytesLib for bytes; using SafeERC20 for IERC20; using BeaconChainProofs for *; @@ -94,7 +102,12 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC * CONSTRUCTOR / INIT * */ - constructor(IETHPOSDeposit _ethPOS, IEigenPodManager _eigenPodManager, uint64 _GENESIS_TIME) { + constructor( + IETHPOSDeposit _ethPOS, + IEigenPodManager _eigenPodManager, + uint64 _GENESIS_TIME, + string memory _version + ) SemVerMixin(_version) { ethPOS = _ethPOS; eigenPodManager = _eigenPodManager; GENESIS_TIME = _GENESIS_TIME; diff --git a/src/contracts/pods/EigenPodManager.sol b/src/contracts/pods/EigenPodManager.sol index 35be0ac084..e6ec820e17 100644 --- a/src/contracts/pods/EigenPodManager.sol +++ b/src/contracts/pods/EigenPodManager.sol @@ -7,6 +7,7 @@ import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; import "../libraries/SlashingLib.sol"; +import "../mixins/SemVerMixin.sol"; import "../permissions/Pausable.sol"; import "./EigenPodPausingConstants.sol"; import "./EigenPodManagerStorage.sol"; @@ -27,7 +28,8 @@ contract EigenPodManager is Pausable, EigenPodPausingConstants, EigenPodManagerStorage, - ReentrancyGuardUpgradeable + ReentrancyGuardUpgradeable, + SemVerMixin { using SlashingLib for *; using Math for *; @@ -48,8 +50,13 @@ contract EigenPodManager is IETHPOSDeposit _ethPOS, IBeacon _eigenPodBeacon, IDelegationManager _delegationManager, - IPauserRegistry _pauserRegistry - ) EigenPodManagerStorage(_ethPOS, _eigenPodBeacon, _delegationManager) Pausable(_pauserRegistry) { + IPauserRegistry _pauserRegistry, + string memory _version + ) + EigenPodManagerStorage(_ethPOS, _eigenPodBeacon, _delegationManager) + Pausable(_pauserRegistry) + SemVerMixin(_version) + { _disableInitializers(); } diff --git a/src/contracts/strategies/EigenStrategy.sol b/src/contracts/strategies/EigenStrategy.sol index f73bccf30c..0720568a2e 100644 --- a/src/contracts/strategies/EigenStrategy.sol +++ b/src/contracts/strategies/EigenStrategy.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.27; // NOTE: Mainnet uses the OpenZeppelin v4.9.0 contracts, but this imports the 4.7.1 version. This will be changed after an upgrade. + import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../interfaces/IStrategyManager.sol"; import "../strategies/StrategyBase.sol"; @@ -37,8 +38,9 @@ contract EigenStrategy is StrategyBase { /// @notice Since this contract is designed to be initializable, the constructor simply sets `strategyManager`, the only immutable variable. constructor( IStrategyManager _strategyManager, - IPauserRegistry _pauserRegistry - ) StrategyBase(_strategyManager, _pauserRegistry) {} + IPauserRegistry _pauserRegistry, + string memory _version + ) StrategyBase(_strategyManager, _pauserRegistry, _version) {} function initialize(IEigen _EIGEN, IERC20 _bEIGEN) public virtual initializer { EIGEN = _EIGEN; diff --git a/src/contracts/strategies/StrategyBase.sol b/src/contracts/strategies/StrategyBase.sol index 555fe6a6e3..b4a9164748 100644 --- a/src/contracts/strategies/StrategyBase.sol +++ b/src/contracts/strategies/StrategyBase.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.27; import "../interfaces/IStrategyManager.sol"; import "../permissions/Pausable.sol"; +import "../mixins/SemVerMixin.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -28,7 +29,7 @@ import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; * [this thread](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706) on the OpenZeppelin repo. * We specifically use a share offset of `SHARES_OFFSET` and a balance offset of `BALANCE_OFFSET`. */ -contract StrategyBase is Initializable, Pausable, IStrategy { +contract StrategyBase is Initializable, Pausable, IStrategy, SemVerMixin { using SafeERC20 for IERC20; uint8 internal constant PAUSED_DEPOSITS = 0; @@ -69,7 +70,11 @@ contract StrategyBase is Initializable, Pausable, IStrategy { } /// @notice Since this contract is designed to be initializable, the constructor simply sets `strategyManager`, the only immutable variable. - constructor(IStrategyManager _strategyManager, IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) { + constructor( + IStrategyManager _strategyManager, + IPauserRegistry _pauserRegistry, + string memory _version + ) Pausable(_pauserRegistry) SemVerMixin(_version) { strategyManager = _strategyManager; _disableInitializers(); } diff --git a/src/contracts/strategies/StrategyBaseTVLLimits.sol b/src/contracts/strategies/StrategyBaseTVLLimits.sol index ac972822e8..65eca55877 100644 --- a/src/contracts/strategies/StrategyBaseTVLLimits.sol +++ b/src/contracts/strategies/StrategyBaseTVLLimits.sol @@ -26,8 +26,9 @@ contract StrategyBaseTVLLimits is StrategyBase { // solhint-disable-next-line no-empty-blocks constructor( IStrategyManager _strategyManager, - IPauserRegistry _pauserRegistry - ) StrategyBase(_strategyManager, _pauserRegistry) {} + IPauserRegistry _pauserRegistry, + string memory _version + ) StrategyBase(_strategyManager, _pauserRegistry, _version) {} function initialize( uint256 _maxPerDeposit, diff --git a/src/contracts/strategies/StrategyFactory.sol b/src/contracts/strategies/StrategyFactory.sol index 20ded2db2e..385bdcd839 100644 --- a/src/contracts/strategies/StrategyFactory.sol +++ b/src/contracts/strategies/StrategyFactory.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; +import "../mixins/SemVerMixin.sol"; import "./StrategyFactoryStorage.sol"; import "./StrategyBase.sol"; import "../permissions/Pausable.sol"; @@ -14,14 +15,18 @@ import "../permissions/Pausable.sol"; * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @dev This may not be compatible with non-standard ERC20 tokens. Caution is warranted. */ -contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable { +contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable, SemVerMixin { uint8 internal constant PAUSED_NEW_STRATEGIES = 0; /// @notice EigenLayer's StrategyManager contract IStrategyManager public immutable strategyManager; /// @notice Since this contract is designed to be initializable, the constructor simply sets the immutable variables. - constructor(IStrategyManager _strategyManager, IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) { + constructor( + IStrategyManager _strategyManager, + IPauserRegistry _pauserRegistry, + string memory _version + ) Pausable(_pauserRegistry) SemVerMixin(_version) { strategyManager = _strategyManager; _disableInitializers(); } diff --git a/src/test/DevnetLifecycle.t.sol b/src/test/DevnetLifecycle.t.sol index 79beb56f99..aeb3cd6752 100644 --- a/src/test/DevnetLifecycle.t.sol +++ b/src/test/DevnetLifecycle.t.sol @@ -119,7 +119,7 @@ contract Devnet_Lifecycle_Test is Test, IAllocationManagerTypes { function _delegateToOperator() internal { // Delegate to operator - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory signatureWithExpiry; cheats.prank(staker); delegationManager.delegateTo(operator, signatureWithExpiry, bytes32(0)); diff --git a/src/test/harnesses/AllocationManagerHarness.sol b/src/test/harnesses/AllocationManagerHarness.sol index abe08266c2..98205c0d22 100644 --- a/src/test/harnesses/AllocationManagerHarness.sol +++ b/src/test/harnesses/AllocationManagerHarness.sol @@ -18,7 +18,8 @@ contract AllocationManagerHarness is AllocationManager { _pauserRegistry, _permissionController, _DEALLOCATION_DELAY, - _ALLOCATION_CONFIGURATION_DELAY + _ALLOCATION_CONFIGURATION_DELAY, + "v9.9.9" ) {} diff --git a/src/test/harnesses/DelegationManagerHarness.sol b/src/test/harnesses/DelegationManagerHarness.sol index a88d0fe67b..dcf1bc0229 100644 --- a/src/test/harnesses/DelegationManagerHarness.sol +++ b/src/test/harnesses/DelegationManagerHarness.sol @@ -20,7 +20,8 @@ contract DelegationManagerHarness is DelegationManager { _allocationManager, _pauserRegistry, _permissionController, - _MIN_WITHDRAWAL_DELAY + _MIN_WITHDRAWAL_DELAY, + "v9.9.9" ) {} diff --git a/src/test/harnesses/EigenPodHarness.sol b/src/test/harnesses/EigenPodHarness.sol index 0be5e4a541..29217270bc 100644 --- a/src/test/harnesses/EigenPodHarness.sol +++ b/src/test/harnesses/EigenPodHarness.sol @@ -9,11 +9,13 @@ contract EigenPodHarness is EigenPod { constructor( IETHPOSDeposit _ethPOS, IEigenPodManager _eigenPodManager, - uint64 _GENESIS_TIME + uint64 _GENESIS_TIME, + string memory _version ) EigenPod( _ethPOS, _eigenPodManager, - _GENESIS_TIME + _GENESIS_TIME, + _version ) {} function getActiveValidatorCount() public view returns (uint256) { diff --git a/src/test/harnesses/EigenPodManagerWrapper.sol b/src/test/harnesses/EigenPodManagerWrapper.sol index ffb190a551..5491984548 100644 --- a/src/test/harnesses/EigenPodManagerWrapper.sol +++ b/src/test/harnesses/EigenPodManagerWrapper.sol @@ -9,8 +9,9 @@ contract EigenPodManagerWrapper is EigenPodManager { IETHPOSDeposit _ethPOS, IBeacon _eigenPodBeacon, IDelegationManager _delegationManager, - IPauserRegistry _pauserRegistry - ) EigenPodManager(_ethPOS, _eigenPodBeacon, _delegationManager, _pauserRegistry) {} + IPauserRegistry _pauserRegistry, + string memory _version + ) EigenPodManager(_ethPOS, _eigenPodBeacon, _delegationManager, _pauserRegistry, _version) {} function setPodOwnerShares(address owner, IEigenPod pod) external { ownerToPod[owner] = pod; diff --git a/src/test/integration/IntegrationDeployer.t.sol b/src/test/integration/IntegrationDeployer.t.sol index 88d03c9a09..90811262cd 100644 --- a/src/test/integration/IntegrationDeployer.t.sol +++ b/src/test/integration/IntegrationDeployer.t.sol @@ -40,6 +40,8 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { bool isUpgraded; uint mainnetForkBlock = 21_616_692; // Post Protocol Council upgrade + string version = "v9.9.9"; + // Beacon chain genesis time when running locally // Multiple of 12 for sanity's sake uint64 constant GENESIS_TIME_LOCAL = 1 hours * 12; @@ -316,35 +318,54 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } /// Deploy an implementation contract for each contract in the system - function _deployImplementations() public noTracing { - allocationManagerImplementation = new AllocationManager(delegationManager, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); - permissionControllerImplementation = new PermissionController(); - delegationManagerImplementation = new DelegationManager(strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); + function _deployImplementations() public { + allocationManagerImplementation = new AllocationManager( + delegationManager, + eigenLayerPauserReg, + permissionController, + DEALLOCATION_DELAY, + ALLOCATION_CONFIGURATION_DELAY, + version + ); + permissionControllerImplementation = new PermissionController(version); + delegationManagerImplementation = new DelegationManager( + strategyManager, + eigenPodManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + version + ); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg, version); rewardsCoordinatorImplementation = new RewardsCoordinator( - delegationManager, - strategyManager, - allocationManager, - eigenLayerPauserReg, - permissionController, - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, - REWARDS_COORDINATOR_MAX_REWARDS_DURATION, - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams({ + delegationManager: delegationManager, + strategyManager: strategyManager, + allocationManager: allocationManager, + pauserRegistry: eigenLayerPauserReg, + permissionController: permissionController, + CALCULATION_INTERVAL_SECONDS: REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, + MAX_REWARDS_DURATION: REWARDS_COORDINATOR_MAX_REWARDS_DURATION, + MAX_RETROACTIVE_LENGTH: REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, + MAX_FUTURE_LENGTH: REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, + GENESIS_REWARDS_TIMESTAMP: REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP, + version: version + }) ); - avsDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg); + avsDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg, version); eigenPodManagerImplementation = new EigenPodManager( DEPOSIT_CONTRACT, eigenPodBeacon, delegationManager, - eigenLayerPauserReg + eigenLayerPauserReg, + "v9.9.9" ); - strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg); + strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg, "v9.9.9"); // Beacon implementations - eigenPodImplementation = new EigenPod(DEPOSIT_CONTRACT, eigenPodManager, BEACON_GENESIS_TIME); - baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg); + eigenPodImplementation = new EigenPod(DEPOSIT_CONTRACT, eigenPodManager, BEACON_GENESIS_TIME, "v9.9.9"); + baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg, "v9.9.9"); // Pre-longtail StrategyBaseTVLLimits implementation // TODO - need to update ExistingDeploymentParser diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IDelegationManager.sol b/src/test/integration/deprecatedInterfaces/mainnet/IDelegationManager.sol index 5f041668c5..3fafbeaf4e 100644 --- a/src/test/integration/deprecatedInterfaces/mainnet/IDelegationManager.sol +++ b/src/test/integration/deprecatedInterfaces/mainnet/IDelegationManager.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import "src/contracts/interfaces/IStrategy.sol"; import "src/contracts/interfaces/IPausable.sol"; -import "src/contracts/interfaces/ISignatureUtils.sol"; +import "src/contracts/interfaces/ISignatureUtilsMixin.sol"; /** * @notice M2 DEPRECATED INTERFACE at commit hash https://github.com/Layr-Labs/eigenlayer-contracts/tree/426f461c59b4f0e16f8becdffd747075edcaded8 @@ -11,7 +11,7 @@ import "src/contracts/interfaces/ISignatureUtils.sol"; * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service */ -interface IDelegationManager_DeprecatedM2 is IPausable, ISignatureUtils { +interface IDelegationManager_DeprecatedM2 is IPausable, ISignatureUtilsMixin { // @notice Struct used for storing information about a single operator who has registered with EigenLayer struct OperatorDetails { /// @notice DEPRECATED -- this field is no longer used, payments are handled in PaymentCoordinator.sol diff --git a/src/test/integration/users/User.t.sol b/src/test/integration/users/User.t.sol index 71ab6a0519..291668fe7d 100644 --- a/src/test/integration/users/User.t.sol +++ b/src/test/integration/users/User.t.sol @@ -205,7 +205,7 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { ) public virtual createSnapshot { print.method("delegateTo", operator.NAME_COLORED()); - ISignatureUtils.SignatureWithExpiry memory emptySig; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory emptySig; delegationManager.delegateTo(address(operator), emptySig, bytes32(0)); print.gasUsed(); } @@ -243,7 +243,7 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { ) public virtual createSnapshot returns (Withdrawal[] memory) { print.method("redelegate", newOperator.NAME_COLORED()); Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(this)); - ISignatureUtils.SignatureWithExpiry memory emptySig; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory emptySig; _tryPrankAppointee_DelegationManager(IDelegationManager.redelegate.selector); delegationManager.redelegate(address(newOperator), emptySig, bytes32(0)); print.gasUsed(); diff --git a/src/test/integration/users/User_M1.t.sol b/src/test/integration/users/User_M1.t.sol index e0ebb17a91..86b6f34904 100644 --- a/src/test/integration/users/User_M1.t.sol +++ b/src/test/integration/users/User_M1.t.sol @@ -5,7 +5,7 @@ import "src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol"; import "src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol"; import "src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol"; import "src/test/integration/users/User.t.sol"; -import "src/contracts/mixins/SignatureUtils.sol"; +import "src/contracts/mixins/SignatureUtilsMixin.sol"; interface IUserM1MainnetForkDeployer { function delegationManager() external view returns (DelegationManager); @@ -70,11 +70,6 @@ contract User_M1 is User { } contract User_M1_AltMethods is User_M1 { - /// @notice The EIP-712 typehash for the contract's domain. - bytes32 internal constant EIP712_DOMAIN_TYPEHASH = - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); - - mapping(bytes32 => bool) public signedHashes; constructor(string memory name) User_M1(name) {} diff --git a/src/test/mocks/DelegationManagerMock.sol b/src/test/mocks/DelegationManagerMock.sol index 74660ae04f..9fc9cd28ce 100644 --- a/src/test/mocks/DelegationManagerMock.sol +++ b/src/test/mocks/DelegationManagerMock.sol @@ -52,7 +52,7 @@ contract DelegationManagerMock is Test { } } - function delegateTo(address operator, ISignatureUtils.SignatureWithExpiry memory /*approverSignatureAndExpiry*/, bytes32 /*approverSalt*/) external { + function delegateTo(address operator, ISignatureUtilsMixinTypes.SignatureWithExpiry memory /*approverSignatureAndExpiry*/, bytes32 /*approverSalt*/) external { delegatedTo[msg.sender] = operator; } diff --git a/src/test/mocks/EigenPodMock.sol b/src/test/mocks/EigenPodMock.sol index d1e12199f9..f74b966c4a 100644 --- a/src/test/mocks/EigenPodMock.sol +++ b/src/test/mocks/EigenPodMock.sol @@ -3,8 +3,10 @@ pragma solidity ^0.8.9; import "forge-std/Test.sol"; import "../../contracts/interfaces/IEigenPod.sol"; +import "../../contracts/mixins/SemVerMixin.sol"; -contract EigenPodMock is IEigenPod, Test { +contract EigenPodMock is IEigenPod, SemVerMixin, Test { + constructor() SemVerMixin("v9.9.9") {} function nonBeaconChainETHBalanceWei() external view returns(uint256) {} diff --git a/src/test/unit/AVSDirectoryUnit.t.sol b/src/test/unit/AVSDirectoryUnit.t.sol index bd9e2b8b05..7a8694d4db 100644 --- a/src/test/unit/AVSDirectoryUnit.t.sol +++ b/src/test/unit/AVSDirectoryUnit.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import "src/contracts/core/AVSDirectory.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; -contract AVSDirectoryUnitTests is EigenLayerUnitTestSetup, IAVSDirectoryEvents, IAVSDirectoryErrors, ISignatureUtils { +contract AVSDirectoryUnitTests is EigenLayerUnitTestSetup, IAVSDirectoryEvents, IAVSDirectoryErrors, ISignatureUtilsMixinTypes { uint8 constant PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS = 0; AVSDirectory avsDirectory; @@ -39,7 +39,7 @@ contract AVSDirectoryUnitTests is EigenLayerUnitTestSetup, IAVSDirectoryEvents, avsd = AVSDirectory( address( new TransparentUpgradeableProxy( - address(new AVSDirectory(IDelegationManager(delegationManager), pauserRegistry)), + address(new AVSDirectory(IDelegationManager(delegationManager), pauserRegistry, "v9.9.9")), address(eigenLayerProxyAdmin), abi.encodeWithSelector( AVSDirectory.initialize.selector, @@ -51,7 +51,18 @@ contract AVSDirectoryUnitTests is EigenLayerUnitTestSetup, IAVSDirectoryEvents, ); isExcludedFuzzAddress[address(avsd)] = true; - assertTrue(avsd.domainSeparator() != bytes32(0), "sanity check"); + bytes memory v = bytes(avsd.version()); + bytes32 expectedDomainSeparator = keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256(bytes("EigenLayer")), + keccak256(bytes.concat(v[0], v[1])), + block.chainid, + address(avsd) + ) + ); + + assertEq(avsd.domainSeparator(), expectedDomainSeparator, "sanity check"); } function _newOperatorRegistrationSignature( @@ -110,7 +121,7 @@ contract AVSDirectoryUnitTests is EigenLayerUnitTestSetup, IAVSDirectoryEvents, function test_registerOperatorToAVS_SignatureExpired() public { defaultOperatorSignature.expiry = block.timestamp - 1; - cheats.expectRevert(SignatureExpired.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); } diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol index 6047e00d3f..7faec4454f 100644 --- a/src/test/unit/AllocationManagerUnit.t.sol +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -62,7 +62,7 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag strategyMock = StrategyBase( address( new TransparentUpgradeableProxy( - address(new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry)), + address(new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry, "v9.9.9")), address(eigenLayerProxyAdmin), abi.encodeWithSelector(StrategyBase.initialize.selector, tokenMock) ) diff --git a/src/test/unit/DelegationUnit.t.sol b/src/test/unit/DelegationUnit.t.sol index 4077bb7437..3342c89586 100644 --- a/src/test/unit/DelegationUnit.t.sol +++ b/src/test/unit/DelegationUnit.t.sol @@ -65,7 +65,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag address defaultOperator2 = address(0x123); address defaultAVS = address(this); string emptyStringForMetadataURI; - ISignatureUtils.SignatureWithExpiry emptyApproverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry emptyApproverSignatureAndExpiry; bytes32 emptySalt; // Helper to use in storage DepositScalingFactor dsf; @@ -112,7 +112,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag // Deploy mock token and strategy tokenMock = new ERC20PresetFixedSupply("Mock Token", "MOCK", tokenMockInitialSupply, address(this)); - strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry, "v9.9.9"); strategyMock = StrategyBase( address( new TransparentUpgradeableProxy( @@ -208,7 +208,7 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag address operator, bytes32 salt, uint256 expiry - ) internal view returns (ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry) { + ) internal view returns (ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry) { approverSignatureAndExpiry.expiry = expiry; { bytes32 digestHash = delegationManager.calculateDelegationApprovalDigestHash( @@ -222,15 +222,20 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag // @notice Assumes operator does not have a delegation approver & staker != approver function _delegateToOperatorWhoAcceptsAllStakers(address staker, address operator) internal { - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry; cheats.prank(staker); delegationManager.delegateTo(operator, approverSignatureAndExpiry, emptySalt); } function _delegateToOperatorWhoRequiresSig(address staker, address operator, bytes32 salt) internal { uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, operator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + operator, + salt, + expiry + ); cheats.prank(staker); delegationManager.delegateTo(operator, approverSignatureAndExpiry, salt); } @@ -1310,6 +1315,19 @@ contract DelegationManagerUnitTests_Initialization_Setters is DelegationManagerU ); assertEq(delegationManager.owner(), address(this), "constructor / initializer incorrect, owner set wrong"); assertEq(delegationManager.paused(), 0, "constructor / initializer incorrect, paused status set wrong"); + + bytes memory v = bytes(delegationManager.version()); + bytes32 expectedDomainSeparator = keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256(bytes("EigenLayer")), + keccak256(bytes.concat(v[0], v[1])), + block.chainid, + address(delegationManager) + ) + ); + + assertEq(delegationManager.domainSeparator(), expectedDomainSeparator, "sanity check"); } /// @notice Verifies that the DelegationManager cannot be iniitalized multiple times @@ -1418,7 +1436,7 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU // delegate from the `staker` to the operator cheats.startPrank(staker); - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry; delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); // expect revert if attempt to register as operator @@ -1592,7 +1610,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { cheats.prank(pauser); delegationManager.pause(2 ** PAUSED_NEW_DELEGATION); - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry; cheats.prank(defaultStaker); cheats.expectRevert(IPausable.CurrentlyPaused.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); @@ -1603,7 +1621,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { */ function testFuzz_Revert_WhenDelegateWhileDelegated( Randomness r, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry ) public rand(r) { address staker = r.Address(); address operator = r.Address(); @@ -1630,7 +1648,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // try to delegate and check that the call reverts cheats.prank(staker); cheats.expectRevert(OperatorNotRegistered.selector); - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry; delegationManager.delegateTo(operator, approverSignatureAndExpiry, emptySalt); } @@ -1648,7 +1666,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { */ function testFuzz_OperatorWhoAcceptsAllStakers_StrategyManagerShares( Randomness r, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry ) public rand(r) { address staker = r.Address(); bytes32 salt = r.Bytes32(); @@ -1711,7 +1729,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { */ function testFuzz_OperatorWhoAcceptsAllStakers_beaconChainStrategyShares( Randomness r, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry ) public rand(r) { address staker = r.Address(); bytes32 salt = r.Bytes32(); @@ -1826,7 +1844,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { */ function testFuzz_Revert_OperatorWhoAcceptsAllStakers_AlreadySlashed100Percent_BeaconChainStrategyShares( Randomness r, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry ) public rand(r) { address staker = r.Address(); bytes32 salt = r.Bytes32(); @@ -2092,7 +2110,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { */ function testFuzz_OperatorWhoAcceptsAllStakers_BeaconChainAndStrategyManagerShares( Randomness r, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry ) public rand(r) { address staker = r.Address(); bytes32 salt = r.Bytes32(); @@ -2275,7 +2293,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { */ function testFuzz_OperatorWhoAcceptsAllStakers_ZeroDelegatableShares( Randomness r, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry ) public rand(r) { address staker = r.Address(); bytes32 salt = r.Bytes32(); @@ -2319,12 +2337,17 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _registerOperatorWithDelegationApprover(defaultOperator); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); } @@ -2348,8 +2371,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // delegate from the `staker` to the operator, undelegate, and then try to delegate again with same approversalt // to check that call reverts @@ -2377,7 +2405,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _registerOperatorWithDelegationApprover(defaultOperator); // calculate the signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry; approverSignatureAndExpiry.expiry = expiry; { bytes32 digestHash = delegationManager.calculateDelegationApprovalDigestHash( @@ -2391,7 +2419,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // try to delegate from the `staker` to the operator, and check reversion cheats.startPrank(staker); - cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.InvalidSignature.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); cheats.stopPrank(); } @@ -2420,8 +2448,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // delegate from the `staker` to the operator cheats.startPrank(staker); @@ -2479,8 +2512,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // Set staker shares in StrategyManager strategyManagerMock.addDeposit(staker, strategyMock, shares); @@ -2562,8 +2600,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // Set staker shares in BeaconChainStrategy eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); @@ -2649,8 +2692,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // Set staker shares in BeaconChainStrategy and StrategyMananger uint256[] memory depositScalingFactors = new uint256[](2); @@ -2744,12 +2792,12 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _registerOperatorWithDelegationApprover(defaultOperator); // create the signature struct - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry; approverSignatureAndExpiry.expiry = expiry; // try to delegate from the `staker` to the operator, and check reversion cheats.startPrank(staker); - cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); cheats.stopPrank(); } @@ -2771,8 +2819,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _registerOperatorWith1271DelegationApprover(defaultOperator); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // delegate from the `staker` to the operator cheats.startPrank(staker); @@ -2801,7 +2854,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { _registerOperator(defaultOperator, address(wallet), emptyStringForMetadataURI); // create the signature struct - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry; approverSignatureAndExpiry.expiry = expiry; // try to delegate from the `staker` to the operator, and check reversion @@ -2830,13 +2883,18 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // calculate the delegationSigner's but this is not the correct signature from the wallet contract // since the wallet owner is address(1) - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // try to delegate from the `staker` to the operator, and check reversion cheats.startPrank(staker); // Signature should fail as the wallet will not return EIP1271_MAGICVALUE - cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.InvalidSignature.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); cheats.stopPrank(); } @@ -2866,8 +2924,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, defaultOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + defaultOperator, + salt, + expiry + ); // delegate from the `staker` to the operator cheats.startPrank(staker); @@ -4505,12 +4568,17 @@ contract DelegationManagerUnitTests_redelegate is DelegationManagerUnitTests { _registerOperatorWithDelegationApprover(newOperator); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, newOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + newOperator, + salt, + expiry + ); // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); delegationManager.redelegate(newOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); } @@ -4532,8 +4600,13 @@ contract DelegationManagerUnitTests_redelegate is DelegationManagerUnitTests { "salt somehow spent too early?" ); // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = - _getApproverSignature(delegationSignerPrivateKey, staker, newOperator, salt, expiry); + ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( + delegationSignerPrivateKey, + staker, + newOperator, + salt, + expiry + ); // Spend salt by delegating normally first cheats.startPrank(staker); diff --git a/src/test/unit/EigenPodManagerUnit.t.sol b/src/test/unit/EigenPodManagerUnit.t.sol index b0fd414e3d..3cf02d6ba8 100644 --- a/src/test/unit/EigenPodManagerUnit.t.sol +++ b/src/test/unit/EigenPodManagerUnit.t.sol @@ -44,7 +44,8 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup, IEigenPodManagerEv ethPOSMock, eigenPodBeacon, IDelegationManager(address(delegationManagerMock)), - pauserRegistry + pauserRegistry, + "v9.9.9" ); eigenPodManager = EigenPodManager( address( @@ -196,7 +197,8 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests { ethPOSMock, eigenPodBeacon, IDelegationManager(address(delegationManagerMock)), - pauserRegistry + pauserRegistry, + "v9.9.9" ); eigenLayerProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerWrapper)); } @@ -368,7 +370,8 @@ contract EigenPodManagerUnitTests_WithdrawSharesAsTokensTests is EigenPodManager ethPOSMock, eigenPodBeacon, IDelegationManager(address(delegationManagerMock)), - pauserRegistry + pauserRegistry, + "v9.9.9" ); eigenLayerProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerWrapper)); } @@ -490,7 +493,8 @@ contract EigenPodManagerUnitTests_BeaconChainETHBalanceUpdateTests is EigenPodMa ethPOSMock, eigenPodBeacon, IDelegationManager(address(delegationManagerMock)), - pauserRegistry + pauserRegistry, + "v9.9.9" ); eigenLayerProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerWrapper)); } diff --git a/src/test/unit/EigenPodUnit.t.sol b/src/test/unit/EigenPodUnit.t.sol index 002ff9419f..eb098cfa94 100644 --- a/src/test/unit/EigenPodUnit.t.sol +++ b/src/test/unit/EigenPodUnit.t.sol @@ -59,7 +59,8 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, podImplementation = new EigenPod( ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), - GENESIS_TIME_LOCAL + GENESIS_TIME_LOCAL, + "v9.9.9" ); // Deploy Beacon @@ -324,7 +325,7 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, contract EigenPodUnitTests_Initialization is EigenPodUnitTests { function test_constructor() public { - EigenPod pod = new EigenPod(ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL); + EigenPod pod = new EigenPod(ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL, "v9.9.9"); assertTrue(pod.ethPOS() == ethPOSDepositMock, "should have set ethPOS correctly"); assertTrue(address(pod.eigenPodManager()) == address(eigenPodManagerMock), "should have set eigenpodmanager correctly"); @@ -352,7 +353,7 @@ contract EigenPodUnitTests_Initialization is EigenPodUnitTests { } function test_initialize_revert_emptyPodOwner() public { - EigenPod pod = new EigenPod(ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL); + EigenPod pod = new EigenPod(ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL, "v9.9.9"); // un-initialize pod cheats.store(address(pod), 0, 0); @@ -1726,7 +1727,8 @@ contract EigenPodHarnessSetup is EigenPodUnitTests { eigenPodHarnessImplementation = new EigenPodHarness( ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), - GENESIS_TIME_LOCAL + GENESIS_TIME_LOCAL, + "v9.9.9" ); // Upgrade eigenPod to harness diff --git a/src/test/unit/RewardsCoordinatorUnit.t.sol b/src/test/unit/RewardsCoordinatorUnit.t.sol index 899d5c0a02..0a86e9e8b4 100644 --- a/src/test/unit/RewardsCoordinatorUnit.t.sol +++ b/src/test/unit/RewardsCoordinatorUnit.t.sol @@ -102,17 +102,21 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin // Deploy RewardsCoordinator proxy and implementation rewardsCoordinatorImplementation = new RewardsCoordinator( - IDelegationManager(address(delegationManagerMock)), - IStrategyManager(address(strategyManagerMock)), - IAllocationManager(address(allocationManagerMock)), - pauserRegistry, - IPermissionController(address(permissionController)), - CALCULATION_INTERVAL_SECONDS, - MAX_REWARDS_DURATION, - MAX_RETROACTIVE_LENGTH, - MAX_FUTURE_LENGTH, - GENESIS_REWARDS_TIMESTAMP - ); + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams({ + delegationManager: IDelegationManager(address(delegationManagerMock)), + strategyManager: IStrategyManager(address(strategyManagerMock)), + allocationManager: IAllocationManager(address(allocationManagerMock)), + pauserRegistry: pauserRegistry, + permissionController: IPermissionController(address(permissionController)), + CALCULATION_INTERVAL_SECONDS: CALCULATION_INTERVAL_SECONDS, + MAX_REWARDS_DURATION: MAX_REWARDS_DURATION, + MAX_RETROACTIVE_LENGTH: MAX_RETROACTIVE_LENGTH, + MAX_FUTURE_LENGTH: MAX_FUTURE_LENGTH, + GENESIS_REWARDS_TIMESTAMP: GENESIS_REWARDS_TIMESTAMP, + version: "v9.9.9" + }) + ); + rewardsCoordinator = RewardsCoordinator( address( new TransparentUpgradeableProxy( @@ -135,7 +139,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin token2 = new ERC20PresetFixedSupply("jeo boden", "MOCK2", mockTokenInitialSupply, address(this)); token3 = new ERC20PresetFixedSupply("pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this)); - strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry, "v9.9.9"); strategyMock1 = StrategyBase( address( new TransparentUpgradeableProxy( diff --git a/src/test/unit/StrategyBaseTVLLimitsUnit.sol b/src/test/unit/StrategyBaseTVLLimitsUnit.sol index 797621b681..531be01dae 100644 --- a/src/test/unit/StrategyBaseTVLLimitsUnit.sol +++ b/src/test/unit/StrategyBaseTVLLimitsUnit.sol @@ -24,7 +24,7 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { StrategyBaseUnitTests.setUp(); // depoloy the TVL-limited strategy - strategyBaseTVLLimitsImplementation = new StrategyBaseTVLLimits(strategyManager, pauserRegistry); + strategyBaseTVLLimitsImplementation = new StrategyBaseTVLLimits(strategyManager, pauserRegistry, "v9.9.9"); strategyWithTVLLimits = StrategyBaseTVLLimits( address( new TransparentUpgradeableProxy( diff --git a/src/test/unit/StrategyBaseUnit.t.sol b/src/test/unit/StrategyBaseUnit.t.sol index 13a80673b3..60caa46201 100644 --- a/src/test/unit/StrategyBaseUnit.t.sol +++ b/src/test/unit/StrategyBaseUnit.t.sol @@ -55,7 +55,7 @@ contract StrategyBaseUnitTests is Test { underlyingToken = new ERC20PresetFixedSupply("Test Token", "TEST", initialSupply, initialOwner); - strategyImplementation = new StrategyBase(strategyManager, pauserRegistry); + strategyImplementation = new StrategyBase(strategyManager, pauserRegistry, "v9.9.9"); strategy = StrategyBase( address( @@ -161,7 +161,7 @@ contract StrategyBaseUnitTests is Test { // Deploy token with 1e39 total supply underlyingToken = new ERC20PresetFixedSupply("Test Token", "TEST", 1e39, initialOwner); - strategyImplementation = new StrategyBase(strategyManager, pauserRegistry); + strategyImplementation = new StrategyBase(strategyManager, pauserRegistry, "v9.9.9"); strategy = StrategyBase( address( diff --git a/src/test/unit/StrategyFactoryUnit.t.sol b/src/test/unit/StrategyFactoryUnit.t.sol index 5775851163..6843c39d20 100644 --- a/src/test/unit/StrategyFactoryUnit.t.sol +++ b/src/test/unit/StrategyFactoryUnit.t.sol @@ -46,12 +46,12 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { underlyingToken = new ERC20PresetFixedSupply("Test Token", "TEST", initialSupply, initialOwner); - strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry, "v9.9.9"); strategyBeacon = new UpgradeableBeacon(address(strategyImplementation)); strategyBeacon.transferOwnership(beaconProxyOwner); - strategyFactoryImplementation = new StrategyFactory(IStrategyManager(address(strategyManagerMock)), pauserRegistry); + strategyFactoryImplementation = new StrategyFactory(IStrategyManager(address(strategyManagerMock)), pauserRegistry, "v9.9.9"); strategyFactory = StrategyFactory( address( diff --git a/src/test/unit/StrategyManagerUnit.t.sol b/src/test/unit/StrategyManagerUnit.t.sol index 99e591dc5b..9e58282aaa 100644 --- a/src/test/unit/StrategyManagerUnit.t.sol +++ b/src/test/unit/StrategyManagerUnit.t.sol @@ -38,7 +38,7 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv function setUp() public override { EigenLayerUnitTestSetup.setUp(); strategyManagerImplementation = new StrategyManager( - IDelegationManager(address(delegationManagerMock)), pauserRegistry + IDelegationManager(address(delegationManagerMock)), pauserRegistry, "v9.9.9" ); strategyManager = StrategyManager( address( @@ -88,7 +88,7 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv IPauserRegistry _pauserRegistry, address admin ) public returns (StrategyBase) { - StrategyBase newStrategyImplementation = new StrategyBase(_strategyManager, _pauserRegistry); + StrategyBase newStrategyImplementation = new StrategyBase(_strategyManager, _pauserRegistry, "v9.9.9"); StrategyBase newStrategy = StrategyBase(address(new TransparentUpgradeableProxy(address(newStrategyImplementation), address(admin), ""))); newStrategy.initialize(_token); return newStrategy; @@ -177,7 +177,7 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv if (!expectedRevertMessageIsempty) { cheats.expectRevert(expectedRevertMessage); } else if (expiry < block.timestamp) { - cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); } else { // needed for expecting an event with the right parameters uint256 expectedDepositShares = amount; @@ -263,6 +263,20 @@ contract StrategyManagerUnitTests_initialize is StrategyManagerUnitTests { address(pauserRegistry), "strategyManager.pauserRegistry() != pauserRegistry" ); + + bytes memory v = bytes(strategyManager.version()); + + bytes32 expectedDomainSeparator = keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256(bytes("EigenLayer")), + keccak256(bytes(bytes.concat(v[0], v[1]))), + block.chainid, + address(strategyManager) + ) + ); + + assertEq(strategyManager.domainSeparator(), expectedDomainSeparator, "sanity check"); } } @@ -836,7 +850,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); - cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.InvalidSignature.selector); // call with `notStaker` as input instead of `staker` address address notStaker = address(3333); strategyManager.depositIntoStrategyWithSignature(strategy, token, amount, notStaker, expiry, signature); @@ -866,7 +880,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa // not expecting a revert, so input an empty string bytes memory signature = _depositIntoStrategyWithSignature(staker, amount, expiry, ""); - cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.InvalidSignature.selector); strategyManager.depositIntoStrategyWithSignature(dummyStrat, dummyToken, amount, staker, expiry, signature); } @@ -906,7 +920,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa signature = abi.encodePacked(r, s, v); } - cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.InvalidSignature.selector); strategyManager.depositIntoStrategyWithSignature(strategy, token, amount, staker, expiry, signature); } @@ -1074,7 +1088,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); - cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); + cheats.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); strategyManager.depositIntoStrategyWithSignature(strategy, token, amount, staker, expiry, signature); uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, strategy); diff --git a/src/test/unit/mixins/SemVerMixin.t.sol b/src/test/unit/mixins/SemVerMixin.t.sol new file mode 100644 index 0000000000..bd217fd1d3 --- /dev/null +++ b/src/test/unit/mixins/SemVerMixin.t.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {Test} from "forge-std/Test.sol"; +import {SemVerMixin} from "src/contracts/mixins/SemVerMixin.sol"; + +// Helper contract to test the abstract SemVerMixin +contract SemVerMixinMock is SemVerMixin { + constructor(string memory version) SemVerMixin(version) {} + + // Expose internal function for testing + function majorVersion() public view returns (string memory) { + return _majorVersion(); + } +} + +contract SemVerMixinTest is Test { + SemVerMixinMock public semVer; + + function test_version_returnsCorrectVersion() public { + semVer = new SemVerMixinMock("v1.2.3"); + assertEq(semVer.version(), "v1.2.3"); + } + + function test_majorVersion_returnsCorrectMajorVersion() public { + semVer = new SemVerMixinMock("v1.2.3"); + assertEq(semVer.majorVersion(), "v1"); + } +} \ No newline at end of file diff --git a/src/test/unit/mixins/SignatureUtilsUnit.t.sol b/src/test/unit/mixins/SignatureUtilsUnit.t.sol index 6e4a50678f..c2b959b39a 100644 --- a/src/test/unit/mixins/SignatureUtilsUnit.t.sol +++ b/src/test/unit/mixins/SignatureUtilsUnit.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; -import "src/contracts/mixins/SignatureUtils.sol"; +import "src/contracts/mixins/SignatureUtilsMixin.sol"; contract MockSigner { mapping(bytes32 => mapping(bytes => bool)) public validSignatures; @@ -16,7 +16,7 @@ contract MockSigner { } } -contract SignatureUtilsUnit is Test, SignatureUtils { +contract SignatureUtilsMixinUnit is Test, SignatureUtilsMixin("v0.0.0") { uint256 signerPk; address signer; bytes32 hash; @@ -34,8 +34,9 @@ contract SignatureUtilsUnit is Test, SignatureUtils { expectedDomainSeparator = keccak256( abi.encode( - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"), + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes("EigenLayer")), + keccak256(bytes(_majorVersion())), block.chainid, address(this) ) @@ -43,7 +44,6 @@ contract SignatureUtilsUnit is Test, SignatureUtils { } function test_domainSeparator_NonZero() public { - assertTrue(_INITIAL_DOMAIN_SEPARATOR != 0, "The initial domain separator should be non-zero"); assertTrue(domainSeparator() != 0, "The domain separator should be non-zero"); assertTrue(domainSeparator() == expectedDomainSeparator, "The domain separator should be as expected"); } @@ -67,7 +67,7 @@ contract SignatureUtilsUnit is Test, SignatureUtils { function test_checkIsValidSignatureNow_Expired() public { (uint8 v, bytes32 r, bytes32 s) = vm.sign(signerPk, digest); - vm.expectRevert(ISignatureUtils.SignatureExpired.selector); + vm.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); _checkIsValidSignatureNow(signer, digest, abi.encode(r, s, v), block.timestamp - 1); } diff --git a/src/test/utils/EigenLayerUnitTestSetup.sol b/src/test/utils/EigenLayerUnitTestSetup.sol index a8ac0e187f..80d48dc3d4 100644 --- a/src/test/utils/EigenLayerUnitTestSetup.sol +++ b/src/test/utils/EigenLayerUnitTestSetup.sol @@ -71,7 +71,7 @@ abstract contract EigenLayerUnitTestSetup is Test { eigenLayerProxyAdmin = new ProxyAdmin(); // Deploy permission controller - permissionControllerImplementation = new PermissionController(); + permissionControllerImplementation = new PermissionController("v9.9.9"); permissionController = PermissionController(address(new TransparentUpgradeableProxy( address(permissionControllerImplementation), address(eigenLayerProxyAdmin),