Skip to content

Commit a44ff71

Browse files
committed
fix: call requestFullOperatorWeightsUpdate on group operations
1 parent 6170061 commit a44ff71

File tree

4 files changed

+135
-18
lines changed

4 files changed

+135
-18
lines changed

src/MetaRegistry.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ contract MetaRegistry is
175175
_updateGroup(groupId, groupInfo);
176176
emit OperatorGroupUpdated(groupId);
177177
}
178+
179+
MODULE.requestFullOperatorWeightsUpdate();
178180
}
179181

180182
/// @inheritdoc IMetaRegistry

test/helpers/mocks/CuratedMock.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ contract CuratedMock is CSMMock {
1717
function mock_setMetaRegistry(address value) external {
1818
metaRegistry = IMetaRegistry(value);
1919
}
20+
21+
function requestFullOperatorWeightsUpdate() external {}
2022
}

test/unit/CuratedModule.t.sol

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,6 +2133,60 @@ contract CuratedDepositableValidatorsCount is
21332133
assertEq(module.getNodeOperator(noId).depositableValidatorsCount, 0);
21342134
assertEq(getStakingModuleSummary().depositableValidatorsCount, 0);
21352135
}
2136+
2137+
function test_updateDepositableValidatorsCount_noNonceIncrementWhen_noWeightChange()
2138+
public
2139+
assertInvariants
2140+
{
2141+
uint256 noId = createNodeOperator(1);
2142+
// After creation the operator has 1 depositable key.
2143+
assertEq(module.getNodeOperator(noId).depositableValidatorsCount, 1);
2144+
2145+
uint256 nonceBefore = module.getNonce();
2146+
2147+
// Default mock: refreshOperatorWeight returns false (no weight change),
2148+
// operator weight is DEFAULT_OPERATOR_WEIGHT (non-zero).
2149+
// Depositable count stays the same so neither condition triggers a
2150+
// nonce increment.
2151+
module.updateDepositableValidatorsCount(noId);
2152+
2153+
assertEq(module.getNonce(), nonceBefore);
2154+
}
2155+
2156+
function test_updateDepositableValidatorsCount_nonceIncrementsWhen_weightChanges()
2157+
public
2158+
assertInvariants
2159+
{
2160+
uint256 noId = createNodeOperator(1);
2161+
assertEq(module.getNodeOperator(noId).depositableValidatorsCount, 1);
2162+
2163+
uint256 nonceBefore = module.getNonce();
2164+
2165+
// Make refreshOperatorWeight report that the weight changed.
2166+
_mockOperatorWeightUpdated(noId, true);
2167+
module.updateDepositableValidatorsCount(noId);
2168+
2169+
assertEq(module.getNonce(), nonceBefore + 1);
2170+
}
2171+
2172+
function test_updateDepositableValidatorsCount_nonceIncrementsOnceWhen_bothDepositableAndWeightChange()
2173+
public
2174+
assertInvariants
2175+
{
2176+
uint256 noId = createNodeOperator(1);
2177+
assertEq(module.getNodeOperator(noId).depositableValidatorsCount, 1);
2178+
2179+
uint256 nonceBefore = module.getNonce();
2180+
2181+
// Make the weight change AND zero it out so depositable goes 1 -> 0.
2182+
_mockOperatorWeightUpdated(noId, true);
2183+
_mockOperatorWeight(noId, 0);
2184+
module.updateDepositableValidatorsCount(noId);
2185+
2186+
// Nonce should increment exactly once, not twice.
2187+
assertEq(module.getNonce(), nonceBefore + 1);
2188+
assertEq(module.getNodeOperator(noId).depositableValidatorsCount, 0);
2189+
}
21362190
}
21372191

21382192
contract CuratedNodeOperatorStateAfterUpdateCurve is

test/unit/MetaRegistry.t.sol

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ import { IStakingModule } from "src/interfaces/IStakingModule.sol";
1616
import { IStakingRouter } from "src/interfaces/IStakingRouter.sol";
1717
import { ILidoLocator } from "src/interfaces/ILidoLocator.sol";
1818

19-
import { CSMMock } from "../helpers/mocks/CSMMock.sol";
19+
import { CuratedMock } from "../helpers/mocks/CuratedMock.sol";
2020
import { AccountingMock } from "../helpers/mocks/AccountingMock.sol";
2121
import { NodeOperatorsRegistryMock } from "../helpers/mocks/NodeOperatorsRegistryMock.sol";
2222
import { StakingRouterMock } from "../helpers/mocks/StakingRouterMock.sol";
2323
import { Utilities } from "../helpers/Utilities.sol";
2424
import { Fixtures } from "../helpers/Fixtures.sol";
2525

2626
contract MetaRegistryTestBase is Test, Utilities, Fixtures {
27-
CSMMock public module;
27+
CuratedMock public module;
2828
StakingRouterMock public stakingRouter;
2929
MetaRegistry public registry;
3030

@@ -51,7 +51,7 @@ contract MetaRegistryTestBase is Test, Utilities, Fixtures {
5151
nodeOperatorOwner = nextAddress("NODE_OPERATOR_OWNER");
5252
stranger = nextAddress("STRANGER");
5353

54-
module = new CSMMock();
54+
module = new CuratedMock();
5555
module.mock_setNodeOperatorsCount(3);
5656
module.mock_setNodeOperatorManagementProperties(
5757
NodeOperatorManagementProperties({
@@ -122,18 +122,7 @@ contract MetaRegistryTestGroupsBase is MetaRegistryTestBase {
122122
ops[0] = _externalOperator(data);
123123
}
124124

125-
function _mockBondCurveWeightHook() internal {
126-
vm.mockCall(
127-
address(module),
128-
abi.encodeWithSelector(
129-
ICuratedModule.requestFullOperatorWeightsUpdate.selector
130-
),
131-
""
132-
);
133-
}
134-
135125
function _setBondCurveWeight(uint256 curveId, uint256 weight) internal {
136-
_mockBondCurveWeightHook();
137126
vm.prank(bondCurveWeightManager);
138127
registry.setBondCurveWeight(curveId, weight);
139128
}
@@ -673,6 +662,17 @@ contract MetaRegistryTestGroupsCreate is MetaRegistryTestGroupsBase {
673662
);
674663
vm.stopPrank();
675664
}
665+
666+
function test_createGroup_CallsRequestFullOperatorWeightsUpdate() public {
667+
vm.expectCall(
668+
address(module),
669+
abi.encodeWithSelector(
670+
ICuratedModule.requestFullOperatorWeightsUpdate.selector
671+
)
672+
);
673+
vm.prank(groupManager);
674+
_createGroup(_subOperatorsArr1(0, MAX_BP), _extOperatorsArr0());
675+
}
676676
}
677677

678678
contract MetaRegistryTestGroupsUpdate is MetaRegistryTestGroupsBase {
@@ -832,6 +832,33 @@ contract MetaRegistryTestGroupsUpdate is MetaRegistryTestGroupsBase {
832832
assertEq(weightsAfter[0], 0);
833833
}
834834

835+
function test_updateGroup_RemovedOperatorCanBeReAddedToNewGroup() public {
836+
_setBondCurveWeight(0, CURVE_WEIGHT);
837+
838+
uint256 groupId1 = registry.getOperatorGroupsCount();
839+
vm.prank(groupManager);
840+
_createGroup(_subOperatorsArr1(0, MAX_BP), _extOperatorsArr0());
841+
842+
// Update group1 to only contain operator 1 (freeing operator 0).
843+
vm.prank(groupManager);
844+
_updateGroup(
845+
groupId1,
846+
_subOperatorsArr1(1, MAX_BP),
847+
_extOperatorsArr0()
848+
);
849+
850+
// Operator 0 should be free to join a new group.
851+
uint256 groupId2 = registry.getOperatorGroupsCount();
852+
vm.prank(groupManager);
853+
_createGroup(_subOperatorsArr1(0, MAX_BP), _extOperatorsArr0());
854+
855+
uint256 membership = registry.getNodeOperatorGroupMembership(0);
856+
assertEq(membership, groupId2);
857+
858+
uint256[] memory weights = registry.getOperatorsWeights(UintArr(0));
859+
assertEq(weights[0], CURVE_WEIGHT);
860+
}
861+
835862
function test_updateGroup_RevertWhen_GroupIdInvalid() public {
836863
vm.startPrank(groupManager);
837864
vm.expectRevert(IMetaRegistry.InvalidOperatorGroupId.selector);
@@ -882,6 +909,42 @@ contract MetaRegistryTestGroupsUpdate is MetaRegistryTestGroupsBase {
882909
);
883910
vm.stopPrank();
884911
}
912+
913+
function test_updateGroup_CallsRequestFullOperatorWeightsUpdate() public {
914+
uint256 newGroupId = registry.getOperatorGroupsCount();
915+
vm.prank(groupManager);
916+
_createGroup(_subOperatorsArr1(0, MAX_BP), _extOperatorsArr0());
917+
918+
vm.expectCall(
919+
address(module),
920+
abi.encodeWithSelector(
921+
ICuratedModule.requestFullOperatorWeightsUpdate.selector
922+
)
923+
);
924+
vm.prank(groupManager);
925+
_updateGroup(
926+
newGroupId,
927+
_subOperatorsArr1(1, MAX_BP),
928+
_extOperatorsArr0()
929+
);
930+
}
931+
932+
function test_updateGroup_CallsRequestFullOperatorWeightsUpdateOnEmptyUpdate()
933+
public
934+
{
935+
uint256 newGroupId = registry.getOperatorGroupsCount();
936+
vm.prank(groupManager);
937+
_createGroup(_subOperatorsArr1(0, MAX_BP), _extOperatorsArr0());
938+
939+
vm.expectCall(
940+
address(module),
941+
abi.encodeWithSelector(
942+
ICuratedModule.requestFullOperatorWeightsUpdate.selector
943+
)
944+
);
945+
vm.prank(groupManager);
946+
_updateGroup(newGroupId, _subOperatorsArr0(), _extOperatorsArr0());
947+
}
885948
}
886949

887950
contract MetaRegistryTestGroupsGetters is MetaRegistryTestGroupsBase {
@@ -1160,16 +1223,13 @@ contract MetaRegistryTestBondCurve is MetaRegistryTestGroupsBase {
11601223
function test_getBondCurveWeight_ReturnsValue() public {
11611224
assertEq(registry.getBondCurveWeight(0), 0);
11621225

1163-
_mockBondCurveWeightHook();
11641226
vm.prank(bondCurveWeightManager);
11651227
registry.setBondCurveWeight(0, 123);
11661228

11671229
assertEq(registry.getBondCurveWeight(0), 123);
11681230
}
11691231

11701232
function test_setBondCurveWeight_EmitsAndCallsHook() public {
1171-
// TODO: Replace mockCall with a real module hook expectation.
1172-
_mockBondCurveWeightHook();
11731233
vm.expectCall(
11741234
address(module),
11751235
abi.encodeWithSelector(
@@ -1191,7 +1251,6 @@ contract MetaRegistryTestBondCurve is MetaRegistryTestGroupsBase {
11911251

11921252
function test_setBondCurveWeight_RevertWhen_SameWeight() public {
11931253
{
1194-
_mockBondCurveWeightHook();
11951254
vm.prank(bondCurveWeightManager);
11961255
registry.setBondCurveWeight(0, 123);
11971256
}

0 commit comments

Comments
 (0)