Skip to content

Commit fa5e324

Browse files
test(incentive-council): improve E2E tests (#1709)
**Motivation:** We need E2E tests to assert the new `EmissionsController` and `RewardsCoordinator` changes work together as expected. **Modifications:** - Improved existing EC integration state checks (which improves every existing test). **Result:** Full E2E coverage of our new changes.
1 parent 4287d2f commit fa5e324

File tree

4 files changed

+482
-208
lines changed

4 files changed

+482
-208
lines changed

src/test/integration/IntegrationBase.t.sol

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,11 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
12041204
}
12051205
}
12061206

1207+
function assert_Snap_OperatorSetRegistered(OperatorSet memory operatorSet, string memory err) internal {
1208+
assertTrue(_getPrevOperatorSetRegistered(operatorSet), err);
1209+
assertTrue(_getOperatorSetRegistered(operatorSet), err);
1210+
}
1211+
12071212
///
12081213
/// SNAPSHOT ASSERTIONS: BEACON CHAIN AND AVS SLASHING
12091214
///
@@ -2724,6 +2729,14 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
27242729
(operatorSets, allocations) = allocationManager.getStrategyAllocations(operator, strategy);
27252730
}
27262731

2732+
function _getPrevOperatorSetRegistered(OperatorSet memory operatorSet) internal timewarp returns (bool) {
2733+
return _getOperatorSetRegistered(operatorSet);
2734+
}
2735+
2736+
function _getOperatorSetRegistered(OperatorSet memory operatorSet) internal view returns (bool) {
2737+
return allocationManager.isOperatorSet(operatorSet);
2738+
}
2739+
27272740
function _getPrevIsSlashable(User operator, OperatorSet memory operatorSet) internal timewarp returns (bool) {
27282741
return _getIsSlashable(operator, operatorSet);
27292742
}
@@ -3322,20 +3335,20 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
33223335
assertEq(prev, cur, err);
33233336
}
33243337

3325-
function assert_Snap_Added_TotalWeight(uint16 added, string memory err) internal {
3326-
uint16 prev = _getPrevTotalWeight();
3327-
uint16 cur = _getTotalWeight();
3338+
function assert_Snap_Added_TotalWeight(uint added, string memory err) internal {
3339+
uint prev = _getPrevTotalWeight();
3340+
uint cur = _getTotalWeight();
33283341
assertEq(prev + added, cur, err);
33293342
}
33303343

3331-
function assert_Snap_Updated_TotalWeight(uint16 expected, string memory err) internal {
3332-
uint16 cur = _getTotalWeight();
3344+
function assert_Snap_Updated_TotalWeight(uint64 expected, string memory err) internal {
3345+
uint cur = _getTotalWeight();
33333346
assertEq(cur, expected, err);
33343347
}
33353348

33363349
function assert_Snap_Unchanged_TotalWeight(string memory err) internal {
3337-
uint16 prev = _getPrevTotalWeight();
3338-
uint16 cur = _getTotalWeight();
3350+
uint prev = _getPrevTotalWeight();
3351+
uint64 cur = _getTotalWeight();
33393352
assertEq(prev, cur, err);
33403353
}
33413354

@@ -3398,8 +3411,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
33983411
}
33993412

34003413
function assert_TotalWeight_LTE_MaxWeight(string memory err) internal view {
3401-
uint16 totalWeight = _getTotalWeight();
3402-
assertTrue(totalWeight <= emissionsController.MAX_TOTAL_WEIGHT(), err);
3414+
uint16 cur = _getTotalWeight();
3415+
assertTrue(cur <= emissionsController.MAX_TOTAL_WEIGHT(), err);
34033416
}
34043417

34053418
function assert_Snap_Updated_EpochTotalProcessed(uint epoch, uint expected, string memory err) internal {

src/test/integration/IntegrationChecks.t.sol

Lines changed: 100 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,56 +1193,67 @@ contract IntegrationCheckUtils is IntegrationBase {
11931193
uint16 expectedTotalWeight
11941194
) internal {
11951195
// === Input Validation ===
1196-
assertEq(distributionIds.length, distributions.length, "check_addDists_State: length mismatch");
1196+
assertEq(distributionIds.length, distributions.length, "length mismatch");
11971197

11981198
// === State Invariants ===
11991199

1200-
// 1. Total weight updated correctly
1201-
assert_Snap_Updated_TotalWeight(expectedTotalWeight, "check_addDists_State: total weight != expected total weight");
1200+
uint currentEpoch = emissionsController.getCurrentEpoch();
12021201

1203-
// 2. Total weight never exceeds maximum
1204-
assert_TotalWeight_LTE_MaxWeight("check_addDists_State: total weight exceeds MAX_TOTAL_WEIGHT");
1202+
// 1. Check that total weight was updated correctly.
1203+
assert_Snap_Updated_TotalWeight(expectedTotalWeight, "total weight != expected total weight");
1204+
1205+
// 2. Check that all checks (found in `EmissionsController._checkDistribution`) were passed before adding.
1206+
// 2a) If the distribution type requires an operator set, check that the operator set was registered before adding.
1207+
// 2b) If emissions have started, check that the start epoch is in the future (we allow adding before emissions start).
1208+
// 2c) Check that the total weight after adding and ensuring it does not exceed the maximum total weight (100%).
1209+
// 2d) Check that the rewards submissions array is not empty for non-Manual distributions.
1210+
// 3. Check that the distributions were stored correctly.
1211+
// 4. Check that N distributions were added.
1212+
// 5. Check that the total processable, emissions controller balance, incentive council balance, current epoch, and button pressability were unchanged.
1213+
uint totalWeightBefore = _getTotalWeight();
1214+
uint totalWeightAdded = 0;
1215+
for (uint i = 0; i < distributionIds.length; ++i) {
1216+
IEmissionsControllerTypes.Distribution memory distribution = distributions[i];
12051217

1206-
// 3. Total distributions increased by number of additions
1207-
assert_Snap_Added_TotalDistributions(distributionIds.length, "check_addDists_State: total distributions should increase");
1218+
// 2a) If the distribution type requires an operator set, check that the operator set was registered before adding.
1219+
if (
1220+
distribution.distributionType == IEmissionsControllerTypes.DistributionType.OperatorSetTotalStake
1221+
|| distribution.distributionType == IEmissionsControllerTypes.DistributionType.OperatorSetUniqueStake
1222+
) assert_Snap_OperatorSetRegistered(distribution.operatorSet, "operator set must be registered");
12081223

1209-
// 4. EmissionsController EIGEN balance unchanged (no minting/transfers on add)
1210-
assert_Snap_Unchanged_EmissionsController_EigenBalance("check_addDists_State: EC balance should be unchanged");
1224+
// 2b) If emissions have started, check that the start epoch is in the future (we allow adding before emissions start).
1225+
if (currentEpoch != type(uint).max) assertGt(distribution.startEpoch, currentEpoch, "start epoch must be in the future");
12111226

1212-
// 5. IncentiveCouncil balance unchanged
1213-
assert_Snap_Unchanged_IncentiveCouncil_EigenBalance(
1214-
emissionsController.incentiveCouncil(), "check_addDists_State: incentive council balance should be unchanged"
1215-
);
1227+
// 2c) Check that the total weight after adding and ensuring it does not exceed the maximum total weight (100%).
1228+
totalWeightAdded += distribution.weight; // Check after the loop.
12161229

1217-
// 6. Current epoch unchanged (adding distributions doesn't advance time)
1218-
assert_Snap_Unchanged_CurrentEpoch("check_addDists_State: current epoch should be unchanged");
1230+
// 2d) Check that the rewards submissions array is not empty for non-Manual distributions.
1231+
if (distribution.distributionType != IEmissionsControllerTypes.DistributionType.Manual) {
1232+
assertGt(distribution.strategiesAndMultipliers.length, 0, "rewards submissions array is empty for non-Manual distributions");
1233+
}
1234+
1235+
// 3. Check that the distributions were stored correctly.
1236+
assert_Distribution_StoredCorrectly(distributionIds[i], distribution, "state should be updated");
1237+
}
1238+
// 2c) Check that the total weight was updated correctly.
1239+
assert_Snap_Added_TotalWeight(totalWeightAdded, "total weight must be added correctly");
1240+
assert_TotalWeight_LTE_MaxWeight("total weight must not exceed the maximum total weight");
12191241

1220-
// 7. Button pressability unchanged (can only add when all processed, so stays not pressable or stays pressable)
1221-
assert_Snap_Unchanged_ButtonPressability("check_addDists_State: button pressability should be unchanged");
1242+
// 4. Check that the total distributions were increased by the number of additions.
1243+
assert_Snap_Added_TotalDistributions(distributionIds.length, "total distributions must be added correctly");
12221244

1223-
// 8. Total processable behavior depends on whether emissions have started
1224-
// Before emissions start, total processable increases with each added distribution
1225-
// After emissions start, total processable stays the same (because both _distributions.length
1226-
// and _epochs[currentEpoch].totalAdded increase by the same amount)
1227-
if (emissionsController.getCurrentEpoch() == type(uint).max) {
1245+
// 5. Check that the total processable, emissions controller balance, incentive council balance, current epoch, and button pressability were unchanged.
1246+
if (currentEpoch == type(uint).max) {
12281247
assert_Snap_Added_TotalProcessableDistributions(
1229-
distributionIds.length, "check_addDists_State: total processable should increase before emissions start"
1248+
distributionIds.length, "total processable should increase before emissions start"
12301249
);
12311250
} else {
1232-
assert_Snap_Unchanged_TotalProcessableDistributions(
1233-
"check_addDists_State: total processable should be unchanged after emissions start"
1234-
);
1235-
}
1236-
1237-
// === Storage Verification ===
1238-
1239-
// 9. All distributions stored correctly with expected values
1240-
assert_Distributions_Match_Expected(distributionIds, distributions, "check_addDists_State");
1241-
1242-
// 10. Each distribution ID is valid (less than total distributions)
1243-
for (uint i = 0; i < distributionIds.length; ++i) {
1244-
assertTrue(distributionIds[i] < _getTotalDistributions(), "check_addDists_State: distribution ID should be valid");
1251+
assert_Snap_Unchanged_TotalProcessableDistributions("total processable should be unchanged after emissions start");
12451252
}
1253+
assert_Snap_Unchanged_EmissionsController_EigenBalance("EC balance should be unchanged");
1254+
assert_Snap_Unchanged_IncentiveCouncil_EigenBalance(emissionsController.incentiveCouncil(), "IC balance should be unchanged");
1255+
assert_Snap_Unchanged_CurrentEpoch("current epoch should be unchanged");
1256+
assert_Snap_Unchanged_ButtonPressability("button pressability should be unchanged");
12461257
}
12471258

12481259
function check_updateDists_State(
@@ -1251,10 +1262,14 @@ contract IntegrationCheckUtils is IntegrationBase {
12511262
IEmissionsControllerTypes.Distribution[] memory newDists
12521263
) internal {
12531264
// === Input Validation ===
1254-
assertEq(distributionIds.length, oldDists.length, "check_updateDists_State: oldDists length mismatch");
1255-
assertEq(distributionIds.length, newDists.length, "check_updateDists_State: newDists length mismatch");
1265+
assertEq(distributionIds.length, oldDists.length, "oldDists length mismatch");
1266+
assertEq(distributionIds.length, newDists.length, "newDists length mismatch");
1267+
1268+
// === State Invariants ===
12561269

1257-
// === Calculate Expected Weight Change ===
1270+
uint currentEpoch = emissionsController.getCurrentEpoch();
1271+
1272+
// 1. Check that total weight was updated correctly (old weights removed, new weights added).
12581273
uint16 totalOldWeight = 0;
12591274
uint16 totalNewWeight = 0;
12601275
for (uint i = 0; i < distributionIds.length; ++i) {
@@ -1263,44 +1278,54 @@ contract IntegrationCheckUtils is IntegrationBase {
12631278
}
12641279
uint16 prevTotalWeight = _getPrevTotalWeight();
12651280
uint16 expectedTotalWeight = prevTotalWeight - totalOldWeight + totalNewWeight;
1281+
assert_Snap_Updated_TotalWeight(expectedTotalWeight, "total weight != expected total weight");
1282+
1283+
// 2. Check that all checks (found in `EmissionsController._checkDistribution`) were passed before updating.
1284+
// 2a) If the distribution type requires an operator set, check that the operator set was registered before updating.
1285+
// 2b) If emissions have started, check that the start epoch is in the future (we allow updating before emissions start).
1286+
// 2c) Check that the total weight after updating and ensuring it does not exceed the maximum total weight (100%).
1287+
// 2d) Check that the rewards submissions array is not empty for non-Manual distributions.
1288+
// 3. Check that the distributions were updated correctly in storage.
1289+
// 4. Check that distribution IDs remain valid.
1290+
// 5. Check that N distributions remain (no addition or removal).
1291+
// 6. Check that the total processable, emissions controller balance, incentive council balance, current epoch, and button pressability were unchanged.
1292+
for (uint i = 0; i < distributionIds.length; ++i) {
1293+
IEmissionsControllerTypes.Distribution memory distribution = newDists[i];
12661294

1267-
// === State Invariants ===
1268-
1269-
// 1. Total weight updated correctly (old weights removed, new weights added)
1270-
assert_Snap_Updated_TotalWeight(expectedTotalWeight, "check_updateDists_State: total weight != expected");
1271-
1272-
// 2. Total weight never exceeds maximum
1273-
assert_TotalWeight_LTE_MaxWeight("check_updateDists_State: total weight exceeds MAX_TOTAL_WEIGHT");
1274-
1275-
// 3. Total distributions unchanged (update doesn't add/remove, just modifies)
1276-
assert_Snap_Unchanged_TotalDistributions("check_updateDists_State: total distributions should be unchanged");
1295+
// 2a) If the distribution type requires an operator set, check that the operator set was registered before updating.
1296+
if (
1297+
distribution.distributionType == IEmissionsControllerTypes.DistributionType.OperatorSetTotalStake
1298+
|| distribution.distributionType == IEmissionsControllerTypes.DistributionType.OperatorSetUniqueStake
1299+
) assert_Snap_OperatorSetRegistered(distribution.operatorSet, "operator set must be registered");
12771300

1278-
// 4. Total processable unchanged (update doesn't affect processability)
1279-
assert_Snap_Unchanged_TotalProcessableDistributions("check_updateDists_State: total processable should be unchanged");
1301+
// 2b) If emissions have started, check that the start epoch is in the future (we allow updating before emissions start).
1302+
if (currentEpoch != type(uint).max) assertGt(distribution.startEpoch, currentEpoch, "start epoch must be in the future");
12801303

1281-
// 5. EmissionsController EIGEN balance unchanged
1282-
assert_Snap_Unchanged_EmissionsController_EigenBalance("check_updateDists_State: EC balance should be unchanged");
1304+
// 2c) Already checked above after the loop (total weight check).
12831305

1284-
// 6. IncentiveCouncil balance unchanged
1285-
assert_Snap_Unchanged_IncentiveCouncil_EigenBalance(
1286-
emissionsController.incentiveCouncil(), "check_updateDists_State: incentive council balance should be unchanged"
1287-
);
1288-
1289-
// 7. Current epoch unchanged
1290-
assert_Snap_Unchanged_CurrentEpoch("check_updateDists_State: current epoch should be unchanged");
1306+
// 2d) Check that the rewards submissions array is not empty for non-Manual distributions.
1307+
if (distribution.distributionType != IEmissionsControllerTypes.DistributionType.Manual) {
1308+
assertGt(distribution.strategiesAndMultipliers.length, 0, "rewards submissions array is empty for non-Manual distributions");
1309+
}
12911310

1292-
// 8. Button pressability unchanged (can only update when all processed)
1293-
assert_Snap_Unchanged_ButtonPressability("check_updateDists_State: button pressability should be unchanged");
1311+
// 3. Check that the distributions were updated correctly in storage.
1312+
assert_Distribution_StoredCorrectly(distributionIds[i], distribution, "distribution should be stored correctly");
12941313

1295-
// === Storage Verification ===
1314+
// 4. Check that distribution IDs remain valid.
1315+
assertTrue(distributionIds[i] < _getTotalDistributions(), "distribution ID should be valid");
1316+
}
1317+
// 2c) Check that the total weight does not exceed the maximum total weight.
1318+
assert_TotalWeight_LTE_MaxWeight("total weight must not exceed the maximum total weight");
12961319

1297-
// 9. All distributions updated correctly with new values
1298-
assert_Distributions_Match_Expected(distributionIds, newDists, "check_updateDists_State");
1320+
// 5. Check that the total distributions were unchanged (update doesn't add/remove, just modifies).
1321+
assert_Snap_Unchanged_TotalDistributions("total distributions must be unchanged");
12991322

1300-
// 10. Distribution IDs remain valid
1301-
for (uint i = 0; i < distributionIds.length; ++i) {
1302-
assertTrue(distributionIds[i] < _getTotalDistributions(), "check_updateDists_State: distribution ID should be valid");
1303-
}
1323+
// 6. Check that the total processable, emissions controller balance, incentive council balance, current epoch, and button pressability were unchanged.
1324+
assert_Snap_Unchanged_TotalProcessableDistributions("total processable should be unchanged");
1325+
assert_Snap_Unchanged_EmissionsController_EigenBalance("EC balance should be unchanged");
1326+
assert_Snap_Unchanged_IncentiveCouncil_EigenBalance(emissionsController.incentiveCouncil(), "IC balance should be unchanged");
1327+
assert_Snap_Unchanged_CurrentEpoch("current epoch should be unchanged");
1328+
assert_Snap_Unchanged_ButtonPressability("button pressability should be unchanged");
13041329
}
13051330

13061331
function check_sweep_State(
@@ -1433,11 +1458,12 @@ contract IntegrationCheckUtils is IntegrationBase {
14331458
// 1. Current epoch matches target epoch
14341459
assertEq(epoch, emissionsController.getCurrentEpoch(), "check_warpToEpoch_State: epoch != current epoch");
14351460

1436-
// 2. Block timestamp is at the start of the target epoch
1437-
assertEq(
1438-
block.timestamp,
1439-
emissionsController.EMISSIONS_START_TIME() + (epoch * emissionsController.EMISSIONS_EPOCH_LENGTH()),
1440-
"check_warpToEpoch_State: block.timestamp != expected timestamp"
1461+
// 2. Block timestamp is within the target epoch's range
1462+
uint epochStart = emissionsController.EMISSIONS_START_TIME() + (epoch * emissionsController.EMISSIONS_EPOCH_LENGTH());
1463+
uint epochEnd = epochStart + emissionsController.EMISSIONS_EPOCH_LENGTH();
1464+
assertTrue(
1465+
block.timestamp >= epochStart && block.timestamp < epochEnd,
1466+
"check_warpToEpoch_State: block.timestamp not within expected epoch range"
14411467
);
14421468

14431469
// === State Invariants ===

0 commit comments

Comments
 (0)