diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index a7359aa8..300125fc 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -29,8 +29,6 @@ contract Deploy is Script { uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); address deployerAddress = vm.addr(deployerPrivateKey); - address[] memory penalizers = new address[](1); - penalizers[0] = deployerAddress; // TODO: temporary vm.startBroadcast(deployerPrivateKey); locator = ILidoLocator(LIDO_LOCATOR_ADDRESS); @@ -45,7 +43,7 @@ contract Deploy is Script { lidoLocator: address(locator), communityStakingModule: address(csm), wstETH: address(wstETH), - penalizeRoleMembers: penalizers + blockedBondRetentionPeriod: 8 weeks }); CSFeeOracle feeOracle = new CSFeeOracle({ secondsPerBlock: 12, @@ -65,6 +63,16 @@ contract Deploy is Script { admin: deployerAddress }); accounting.setFeeDistributor(address(feeDistributor)); + // TODO: temporary + accounting.grantRole(accounting.PENALIZE_BOND_ROLE(), deployerAddress); + accounting.grantRole( + accounting.EL_REWARDS_STEALING_PENALTY_ROLE(), + deployerAddress + ); + accounting.grantRole( + accounting.EASY_TRACK_MOTION_AGENT_ROLE(), + deployerAddress + ); // TODO: csm.setBondManager(address(accounting)); vm.stopBroadcast(); diff --git a/src/CSAccounting.sol b/src/CSAccounting.sol index bf229d58..34f174a2 100644 --- a/src/CSAccounting.sol +++ b/src/CSAccounting.sol @@ -28,11 +28,6 @@ contract CSAccountingBase { address from, uint256 amount ); - event BondPenalized( - uint256 indexed nodeOperatorId, - uint256 penaltyShares, - uint256 burnedShares - ); event StETHRewardsClaimed( uint256 indexed nodeOperatorId, address to, @@ -48,6 +43,25 @@ contract CSAccountingBase { address to, uint256 amount ); + event ELRewardsStealingReported( + uint256 indexed nodeOperatorId, + uint256 proposedBlockNumber, + uint256 stolenAmount + ); + event BlockedBondChanged( + uint256 indexed nodeOperatorId, + uint256 newETHAmount, + uint256 retentionUntil + ); + event BlockedBondCompensated( + uint256 indexed nodeOperatorId, + uint256 ETHAmount + ); + event BondPenalized( + uint256 indexed nodeOperatorId, + uint256 penaltyETH, + uint256 coveringETH + ); } contract CSAccounting is CSAccountingBase, AccessControlEnumerable { @@ -58,19 +72,30 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { bytes32 r; bytes32 s; } + struct BlockedBondEther { + uint256 ETHAmount; + uint256 retentionUntil; + } bytes32 public constant PENALIZE_BOND_ROLE = keccak256("PENALIZE_BOND_ROLE"); + bytes32 public constant EL_REWARDS_STEALING_PENALTY_ROLE = + keccak256("EL_REWARDS_STEALING_PENALTY_ROLE"); + bytes32 public constant EASY_TRACK_MOTION_AGENT_ROLE = + keccak256("EASY_TRACK_MOTION_AGENT_ROLE"); + + uint256 public immutable COMMON_BOND_SIZE; + uint256 public immutable BLOCKED_BOND_RETENTION_PERIOD; ILidoLocator private immutable LIDO_LOCATOR; ICSModule private immutable CSM; IWstETH private immutable WSTETH; - uint256 private immutable COMMON_BOND_SIZE; address public FEE_DISTRIBUTOR; uint256 public totalBondShares; mapping(uint256 => uint256) private _bondShares; + mapping(uint256 => BlockedBondEther) private _blockedBondEther; error NotOwnerToClaim(address msgSender, address owner); @@ -79,14 +104,14 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { /// @param lidoLocator lido locator contract address /// @param wstETH wstETH contract address /// @param communityStakingModule community staking module contract address - /// @param penalizeRoleMembers list of addresses with PENALIZE_BOND_ROLE + /// @param blockedBondRetentionPeriod retention period for blocked bond in seconds constructor( uint256 commonBondSize, address admin, address lidoLocator, address wstETH, address communityStakingModule, - address[] memory penalizeRoleMembers + uint256 blockedBondRetentionPeriod ) { // check zero addresses require(admin != address(0), "admin is zero address"); @@ -97,24 +122,18 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { ); require(wstETH != address(0), "wstETH is zero address"); require( - penalizeRoleMembers.length > 0, - "penalize role members is empty" + blockedBondRetentionPeriod > 7 days, + "blocked bond retention period should be greater than 7 days" ); _setupRole(DEFAULT_ADMIN_ROLE, admin); - for (uint256 i; i < penalizeRoleMembers.length; ++i) { - require( - penalizeRoleMembers[i] != address(0), - "penalize role member is zero address" - ); - _setupRole(PENALIZE_BOND_ROLE, penalizeRoleMembers[i]); - } LIDO_LOCATOR = ILidoLocator(lidoLocator); CSM = ICSModule(communityStakingModule); WSTETH = IWstETH(wstETH); COMMON_BOND_SIZE = commonBondSize; + BLOCKED_BOND_RETENTION_PERIOD = blockedBondRetentionPeriod; } function setFeeDistributor( @@ -139,7 +158,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { bytes32[] memory rewardsProof, uint256 nodeOperatorId, uint256 cumulativeFeeShares - ) public view returns (uint256) { + ) public view onlyExistingNodeOperator(nodeOperatorId) returns (uint256) { (uint256 current, uint256 required) = _bondSharesSummary( _getNodeOperatorActiveKeys(nodeOperatorId) ); @@ -219,7 +238,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { /// @return missing bond ETH. function getMissingBondETH( uint256 nodeOperatorId - ) public view returns (uint256) { + ) public view onlyExistingNodeOperator(nodeOperatorId) returns (uint256) { (uint256 current, uint256 required) = _bondETHSummary(nodeOperatorId); return required > current ? required - current : 0; } @@ -242,6 +261,18 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { return WSTETH.getWstETHByStETH(getMissingBondStETH(nodeOperatorId)); } + /// @notice Returns the amount of ETH blocked by the given node operator. + function getBlockedBondETH( + uint256 nodeOperatorId + ) public view returns (uint256) { + if ( + _blockedBondEther[nodeOperatorId].retentionUntil > block.timestamp + ) { + return _blockedBondEther[nodeOperatorId].ETHAmount; + } + return 0; + } + /// @notice Returns the required bond ETH (inc. missed and excess) for the given node operator to upload new keys. /// @param nodeOperatorId id of the node operator to get required bond for. /// @return required bond ETH. @@ -250,21 +281,10 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 additionalKeysCount ) public view returns (uint256) { (uint256 current, uint256 required) = _bondETHSummary(nodeOperatorId); - uint256 requiredForKeys = getRequiredBondETHForKeys( - additionalKeysCount - ); - - uint256 missing = required > current ? required - current : 0; - if (missing > 0) { - return missing + requiredForKeys; - } - - uint256 excess = current - required; - if (excess >= requiredForKeys) { - return 0; - } - - return requiredForKeys - excess; + required += + getRequiredBondETHForKeys(additionalKeysCount) + + getBlockedBondETH(nodeOperatorId); + return required > current ? required - current : 0; } /// @notice Returns the required bond stETH (inc. missed and excess) for the given node operator to upload new keys. @@ -362,13 +382,13 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { function depositETH( address from, uint256 nodeOperatorId - ) external payable returns (uint256) { + ) + external + payable + onlyExistingNodeOperator(nodeOperatorId) + returns (uint256) + { from = (from == address(0)) ? msg.sender : from; - // TODO: should be modifier. condition might be changed as well - require( - nodeOperatorId < CSM.getNodeOperatorsCount(), - "node operator does not exist" - ); uint256 shares = _lido().submit{ value: msg.value }(address(0)); _bondShares[nodeOperatorId] += shares; totalBondShares += shares; @@ -383,7 +403,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { address from, uint256 nodeOperatorId, uint256 stETHAmount - ) external returns (uint256) { + ) external onlyExistingNodeOperator(nodeOperatorId) returns (uint256) { from = (from == address(0)) ? msg.sender : from; return _depositStETH(from, nodeOperatorId, stETHAmount); } @@ -397,7 +417,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 nodeOperatorId, uint256 stETHAmount, PermitInput calldata permit - ) external returns (uint256) { + ) external onlyExistingNodeOperator(nodeOperatorId) returns (uint256) { from = (from == address(0)) ? msg.sender : from; // solhint-disable-next-line func-named-parameters _lido().permit( @@ -417,10 +437,6 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 nodeOperatorId, uint256 stETHAmount ) internal returns (uint256) { - require( - nodeOperatorId < CSM.getNodeOperatorsCount(), - "node operator does not exist" - ); uint256 shares = _sharesByEth(stETHAmount); _lido().transferSharesFrom(from, address(this), shares); _bondShares[nodeOperatorId] += shares; @@ -437,7 +453,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { address from, uint256 nodeOperatorId, uint256 wstETHAmount - ) external returns (uint256) { + ) external onlyExistingNodeOperator(nodeOperatorId) returns (uint256) { from = (from == address(0)) ? msg.sender : from; return _depositWstETH(from, nodeOperatorId, wstETHAmount); } @@ -452,7 +468,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 nodeOperatorId, uint256 wstETHAmount, PermitInput calldata permit - ) external returns (uint256) { + ) external onlyExistingNodeOperator(nodeOperatorId) returns (uint256) { // solhint-disable-next-line func-named-parameters WSTETH.permit( from, @@ -471,10 +487,6 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 nodeOperatorId, uint256 wstETHAmount ) internal returns (uint256) { - require( - nodeOperatorId < CSM.getNodeOperatorsCount(), - "node operator does not exist" - ); WSTETH.transferFrom(from, address(this), wstETHAmount); uint256 stETHAmount = WSTETH.unwrap(wstETHAmount); uint256 shares = _sharesByEth(stETHAmount); @@ -494,7 +506,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 nodeOperatorId, uint256 cumulativeFeeShares, uint256 stETHAmount - ) external { + ) external onlyExistingNodeOperator(nodeOperatorId) { ( address managerAddress, address rewardAddress @@ -505,7 +517,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { nodeOperatorId, cumulativeFeeShares ); - if (claimableShares == 0) { + if (claimableShares == 0 || getBlockedBondETH(nodeOperatorId) > 0) { emit StETHRewardsClaimed(nodeOperatorId, rewardAddress, 0); return; } @@ -532,7 +544,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 nodeOperatorId, uint256 cumulativeFeeShares, uint256 wstETHAmount - ) external { + ) external onlyExistingNodeOperator(nodeOperatorId) { ( address managerAddress, address rewardAddress @@ -543,7 +555,7 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { nodeOperatorId, cumulativeFeeShares ); - if (claimableShares == 0) { + if (claimableShares == 0 || getBlockedBondETH(nodeOperatorId) > 0) { emit WstETHRewardsClaimed(nodeOperatorId, rewardAddress, 0); return; } @@ -568,7 +580,11 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { uint256 nodeOperatorId, uint256 cumulativeFeeShares, uint256 ETHAmount - ) external returns (uint256[] memory requestIds) { + ) + external + onlyExistingNodeOperator(nodeOperatorId) + returns (uint256[] memory requestIds) + { ( address managerAddress, address rewardAddress @@ -579,6 +595,10 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { nodeOperatorId, cumulativeFeeShares ); + if (claimableShares == 0 || getBlockedBondETH(nodeOperatorId) > 0) { + emit ETHRewardsRequested(nodeOperatorId, rewardAddress, 0); + return requestIds; + } uint256 toClaim = ETHAmount < _ethByShares(claimableShares) ? _sharesByEth(ETHAmount) : claimableShares; @@ -594,23 +614,153 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { return requestIds; } - /// @notice Penalize bond by burning shares + /// @notice Reports EL rewards stealing for the given node operator. + /// @param nodeOperatorId id of the node operator to report EL rewards stealing for. + /// @param proposedBlockNumber block number of the proposed block with EL rewards stealing. + /// @param stolenAmount amount of stolen EL rewards. + function initELRewardsStealingPenalty( + uint256 nodeOperatorId, + uint256 proposedBlockNumber, + uint256 stolenAmount + ) + external + onlyRole(EL_REWARDS_STEALING_PENALTY_ROLE) + onlyExistingNodeOperator(nodeOperatorId) + { + require(stolenAmount > 0, "stolen amount should be greater than zero"); + emit ELRewardsStealingReported( + nodeOperatorId, + proposedBlockNumber, + stolenAmount + ); + _changeBlockedBondState({ + nodeOperatorId: nodeOperatorId, + ETHAmount: _blockedBondEther[nodeOperatorId].ETHAmount + + stolenAmount, + retentionUntil: block.timestamp + BLOCKED_BOND_RETENTION_PERIOD + }); + } + + /// @notice Releases blocked bond ETH for the given node operator. + /// @param nodeOperatorId id of the node operator to release blocked bond for. + /// @param amount amount of ETH to release. + function releaseBlockedBondETH( + uint256 nodeOperatorId, + uint256 amount + ) + external + onlyRole(EL_REWARDS_STEALING_PENALTY_ROLE) + onlyExistingNodeOperator(nodeOperatorId) + { + _releaseBlockedBondETH(nodeOperatorId, amount); + } + + /// @notice Compensates blocked bond ETH for the given node operator. + /// @param nodeOperatorId id of the node operator to compensate blocked bond for. + function compensateBlockedBondETH( + uint256 nodeOperatorId + ) external payable onlyExistingNodeOperator(nodeOperatorId) { + require(msg.value > 0, "value should be greater than zero"); + payable(LIDO_LOCATOR.elRewardsVault()).transfer(msg.value); + _releaseBlockedBondETH(nodeOperatorId, msg.value); + } + + function _releaseBlockedBondETH( + uint256 nodeOperatorId, + uint256 amount + ) internal { + uint256 blocked = getBlockedBondETH(nodeOperatorId); + require(blocked > 0, "no blocked bond to release"); + require( + _blockedBondEther[nodeOperatorId].ETHAmount >= amount, + "blocked bond is less than amount to compensate" + ); + _changeBlockedBondState( + nodeOperatorId, + _blockedBondEther[nodeOperatorId].ETHAmount - amount, + _blockedBondEther[nodeOperatorId].retentionUntil + ); + } + + /// @dev Should be called by the committee. Doesn't settle blocked bond if it is in the safe frame (1 day) + /// @notice Settles blocked bond for the given node operators. + /// @param nodeOperatorIds ids of the node operators to settle blocked bond for. + function settleBlockedBondETH( + uint256[] memory nodeOperatorIds + ) external onlyRole(EASY_TRACK_MOTION_AGENT_ROLE) { + uint256 nosCount = CSM.getNodeOperatorsCount(); + for (uint256 i; i < nodeOperatorIds.length; ++i) { + uint256 nodeOperatorId = nodeOperatorIds[i]; + if (nodeOperatorId >= nosCount) { + continue; + } + BlockedBondEther storage data = _blockedBondEther[nodeOperatorId]; + if ( + block.timestamp + + BLOCKED_BOND_RETENTION_PERIOD - + data.retentionUntil < + 1 days + ) { + // blocked bond in safe frame to manage it by committee or node operator + continue; + } + uint256 blockedAmount = getBlockedBondETH(nodeOperatorId); + _changeBlockedBondState({ + nodeOperatorId: nodeOperatorId, + ETHAmount: blockedAmount > 0 + ? penalize(nodeOperatorId, blockedAmount) + : 0, + retentionUntil: data.retentionUntil + }); + } + } + + function _changeBlockedBondState( + uint256 nodeOperatorId, + uint256 ETHAmount, + uint256 retentionUntil + ) internal { + if (ETHAmount == 0) { + delete _blockedBondEther[nodeOperatorId]; + emit BlockedBondChanged(nodeOperatorId, 0, 0); + return; + } + _blockedBondEther[nodeOperatorId] = BlockedBondEther({ + ETHAmount: ETHAmount, + retentionUntil: retentionUntil + }); + emit BlockedBondChanged(nodeOperatorId, ETHAmount, retentionUntil); + } + + /// @notice Penalize bond by burning shares of the given node operator. /// @param nodeOperatorId id of the node operator to penalize bond for. - /// @param shares amount shares to burn. + /// @param ETHAmount amount of ETH to penalize. + /// @return uncovered amount. function penalize( uint256 nodeOperatorId, - uint256 shares - ) external onlyRole(PENALIZE_BOND_ROLE) { - uint256 currentBond = getBondShares(nodeOperatorId); - uint256 coveringShares = shares < currentBond ? shares : currentBond; + uint256 ETHAmount + ) + public + onlyRole(PENALIZE_BOND_ROLE) + onlyExistingNodeOperator(nodeOperatorId) + returns (uint256) + { + uint256 penaltyShares = _sharesByEth(ETHAmount); + uint256 currentShares = getBondShares(nodeOperatorId); + uint256 sharesToBurn = penaltyShares < currentShares + ? penaltyShares + : currentShares; _lido().transferSharesFrom( address(this), LIDO_LOCATOR.burner(), - coveringShares + sharesToBurn ); - _bondShares[nodeOperatorId] -= coveringShares; - totalBondShares -= coveringShares; - emit BondPenalized(nodeOperatorId, shares, coveringShares); + _bondShares[nodeOperatorId] -= sharesToBurn; + totalBondShares -= sharesToBurn; + uint256 penaltyEth = _ethByShares(penaltyShares); + uint256 coveringEth = _ethByShares(sharesToBurn); + emit BondPenalized(nodeOperatorId, penaltyEth, coveringEth); + return penaltyEth - coveringEth; } function _lido() internal view returns (ILido) { @@ -694,4 +844,12 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable { function _ethByShares(uint256 shares) internal view returns (uint256) { return _lido().getPooledEthByShares(shares); } + + modifier onlyExistingNodeOperator(uint256 nodeOperatorId) { + require( + nodeOperatorId < CSM.getNodeOperatorsCount(), + "node operator does not exist" + ); + _; + } } diff --git a/test/CSAccounting.t.sol b/test/CSAccounting.t.sol index e2ff1a02..86859dbd 100644 --- a/test/CSAccounting.t.sol +++ b/test/CSAccounting.t.sol @@ -45,9 +45,6 @@ contract CSAccountingTest is user = address(2); stranger = address(777); - address[] memory penalizeRoleMembers = new address[](1); - penalizeRoleMembers[0] = admin; - (locator, wstETH, stETH, burner) = initLido(); stakingModule = new CommunityStakingModuleMock(); @@ -57,14 +54,21 @@ contract CSAccountingTest is address(locator), address(wstETH), address(stakingModule), - penalizeRoleMembers + 8 weeks ); feeDistributor = new CommunityStakingFeeDistributorMock( address(locator), address(accounting) ); - vm.prank(admin); + vm.startPrank(admin); accounting.setFeeDistributor(address(feeDistributor)); + accounting.grantRole(accounting.PENALIZE_BOND_ROLE(), admin); + accounting.grantRole( + accounting.EL_REWARDS_STEALING_PENALTY_ROLE(), + admin + ); + accounting.grantRole(accounting.EASY_TRACK_MOTION_AGENT_ROLE(), admin); + vm.stopPrank(); } function test_totalBondShares() public { @@ -1048,26 +1052,28 @@ contract CSAccountingTest is accounting.depositStETH(user, 0, 32 ether); vm.stopPrank(); + uint256 shares = stETH.getSharesByPooledEth(1 ether); + uint256 penalized = stETH.getPooledEthByShares(shares); vm.expectEmit(true, true, true, true, address(accounting)); - emit BondPenalized(0, 1e18, 1e18); + emit BondPenalized(0, penalized, penalized); uint256 bondSharesBefore = accounting.getBondShares(0); vm.prank(admin); - accounting.penalize(0, 1e18); + accounting.penalize(0, 1 ether); assertEq( accounting.getBondShares(0), - bondSharesBefore - 1e18, + bondSharesBefore - shares, "bond shares should be decreased by penalty" ); assertEq( stETH.sharesOf(address(accounting)), - bondSharesBefore - 1e18, + bondSharesBefore - shares, "bond manager shares should be decreased by penalty" ); assertEq( stETH.sharesOf(address(burner)), - 1e18, + shares, "burner shares should be equal to penalty" ); } @@ -1081,12 +1087,16 @@ contract CSAccountingTest is vm.stopPrank(); uint256 bondSharesBefore = accounting.getBondShares(0); - + uint256 penaltyShares = stETH.getSharesByPooledEth(33 ether); vm.expectEmit(true, true, true, true, address(accounting)); - emit BondPenalized(0, 32 * 1e18, bondSharesBefore); + emit BondPenalized( + 0, + stETH.getPooledEthByShares(penaltyShares), + stETH.getPooledEthByShares(bondSharesBefore) + ); vm.prank(admin); - accounting.penalize(0, 32 * 1e18); + accounting.penalize(0, 33 ether); assertEq( accounting.getBondShares(0), @@ -1114,11 +1124,12 @@ contract CSAccountingTest is vm.stopPrank(); uint256 shares = stETH.getSharesByPooledEth(32 ether); + uint256 penalized = stETH.getPooledEthByShares(shares); vm.expectEmit(true, true, true, true, address(accounting)); - emit BondPenalized(0, shares, shares); + emit BondPenalized(0, penalized, penalized); vm.prank(admin); - accounting.penalize(0, shares); + accounting.penalize(0, 32 ether); assertEq( accounting.getBondShares(0), diff --git a/test/CSMAddValidator.t.sol b/test/CSMAddValidator.t.sol index 7398533a..034c24ca 100644 --- a/test/CSMAddValidator.t.sol +++ b/test/CSMAddValidator.t.sol @@ -49,7 +49,7 @@ contract CSMCommon is Test, Fixtures, Utilities, CSModuleBase { address(locator), address(wstETH), address(csm), - penalizeRoleMembers + 8 weeks ); csm.setAccounting(address(accounting)); } diff --git a/test/CSMInit.t.sol b/test/CSMInit.t.sol index c7d88191..bb46ec9f 100644 --- a/test/CSMInit.t.sol +++ b/test/CSMInit.t.sol @@ -42,7 +42,7 @@ contract CSMInitTest is Test, Fixtures { address(locator), address(wstETH), address(csm), - penalizeRoleMembers + 8 weeks ); } diff --git a/test/integration/DepositInTokens.t.sol b/test/integration/DepositInTokens.t.sol index 68c76806..529870e0 100644 --- a/test/integration/DepositInTokens.t.sol +++ b/test/integration/DepositInTokens.t.sol @@ -55,8 +55,6 @@ contract DepositIntegrationTest is Test, PermitHelper { user = vm.addr(userPrivateKey); strangerPrivateKey = 0x517a4637; stranger = vm.addr(strangerPrivateKey); - address[] memory penalizeRoleMembers = new address[](1); - penalizeRoleMembers[0] = user; accounting = new CSAccounting( 2 ether, @@ -64,7 +62,7 @@ contract DepositIntegrationTest is Test, PermitHelper { address(locator), address(wstETH), address(csm), - penalizeRoleMembers + 8 weeks ); csm.setNodeOperator({ diff --git a/test/integration/StakingRouter.t.sol b/test/integration/StakingRouter.t.sol index 88e189b7..700d58d2 100644 --- a/test/integration/StakingRouter.t.sol +++ b/test/integration/StakingRouter.t.sol @@ -49,15 +49,13 @@ contract StakingRouterIntegrationTest is Test, Utilities { vm.label(address(stakingRouter), "stakingRouter"); csm = new CSModule("community-staking-module", address(locator)); - address[] memory penalizeRoleMembers = new address[](1); - penalizeRoleMembers[0] = address(csm); CSAccounting accounting = new CSAccounting( 2 ether, address(csm), address(locator), address(wstETH), address(csm), - penalizeRoleMembers + 8 weeks ); csm.setAccounting(address(accounting));